using System;
using System.Linq;
using System.Collections.Generic;
public class Test
{
public class Stock {
public string Name {get; set;}
public List<int> Values {get; set;}
public float Price {get; set;}
public override bool Equals(object obj) {
if (obj == this) return true;
var other = obj as Stock;
if (other == null) return false;
return Name.Equals(other.Name)
&& Price == other.Price
&& Values.SequenceEqual(other.Values);
}
public override int GetHashCode() {
return Name.GetHashCode()
+ Price.GetHashCode()
+ Values.Sum();
}
}
// Stock collection
public static void Main()
{
var stocks = new List<Stock> {
new Stock(){Name="Prod1", Values=new List<int>{1, 2, 3, 0}, Price=5.0f},
new Stock(){Name="Prod1", Values=new List<int>{1, 2, 3, 0}, Price=5.0f},
new Stock(){Name="Prod11", Values=new List<int>{1, 0, 3, 1}, Price=8.0f},
new Stock(){Name="Prod11", Values=new List<int>{1, 0, 3, 1}, Price=8.0f},
new Stock(){Name="Prod18", Values=new List<int>{0, 0, 4, 1}, Price=4.5f},
new Stock(){Name="Prod20", Values=new List<int>{4, 0, 0, 2}, Price=9.9f},
new Stock(){Name="Prod20", Values=new List<int>{4, 0, 0, 2}, Price=9.9f},
new Stock(){Name="Prod29", Values=new List<int>{2, 1, 0, 1}, Price=7.2f}
};
var res = stocks.GroupBy(x => x, (x, g) => new { Count = g.Count(), Values = x}).ToList();
foreach (var item in res) {
Console.WriteLine("{0} {1} at {2} ({3})", item.Count, item.Values.Name, item.Values.Price, string.Join(", ", item.Values.Values.ToArray()));
}
}
}
dXNpbmcgU3lzdGVtOwp1c2luZyBTeXN0ZW0uTGlucTsKdXNpbmcgU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWM7CgoKcHVibGljIGNsYXNzIFRlc3QKewoJCgkKCXB1YmxpYyBjbGFzcyBTdG9jayB7CiAgICBwdWJsaWMgc3RyaW5nIE5hbWUge2dldDsgc2V0O30KICAgIHB1YmxpYyBMaXN0PGludD4gVmFsdWVzIHtnZXQ7IHNldDt9CiAgICBwdWJsaWMgZmxvYXQgUHJpY2Uge2dldDsgc2V0O30KICAgIAogICAgICAgIHB1YmxpYyBvdmVycmlkZSBib29sIEVxdWFscyhvYmplY3Qgb2JqKSB7CiAgICAgICAgaWYgKG9iaiA9PSB0aGlzKSByZXR1cm4gdHJ1ZTsKICAgICAgICB2YXIgb3RoZXIgPSBvYmogYXMgU3RvY2s7CiAgICAgICAgaWYgKG90aGVyID09IG51bGwpIHJldHVybiBmYWxzZTsKICAgICAgICByZXR1cm4gTmFtZS5FcXVhbHMob3RoZXIuTmFtZSkKICAgICAgICAgICAgJiYgUHJpY2UgPT0gb3RoZXIuUHJpY2UKICAgICAgICAgICAgJiYgVmFsdWVzLlNlcXVlbmNlRXF1YWwob3RoZXIuVmFsdWVzKTsKICAgIH0KICAgIHB1YmxpYyBvdmVycmlkZSBpbnQgR2V0SGFzaENvZGUoKSB7CiAgICAgICAgcmV0dXJuIE5hbWUuR2V0SGFzaENvZGUoKQogICAgICAgICAgICAgKyBQcmljZS5HZXRIYXNoQ29kZSgpCiAgICAgICAgICAgICArIFZhbHVlcy5TdW0oKTsKICAgIH0KICAgIAogICAgCn0KCi8vIFN0b2NrIGNvbGxlY3Rpb24KCQoJCgkKCXB1YmxpYyBzdGF0aWMgdm9pZCBNYWluKCkKCXsKCnZhciBzdG9ja3MgPSBuZXcgTGlzdDxTdG9jaz4gewogICAgbmV3IFN0b2NrKCl7TmFtZT0iUHJvZDEiLCBWYWx1ZXM9bmV3IExpc3Q8aW50PnsxLCAyLCAzLCAwfSwgUHJpY2U9NS4wZn0sIAogICAgbmV3IFN0b2NrKCl7TmFtZT0iUHJvZDEiLCBWYWx1ZXM9bmV3IExpc3Q8aW50PnsxLCAyLCAzLCAwfSwgUHJpY2U9NS4wZn0sCiAgICBuZXcgU3RvY2soKXtOYW1lPSJQcm9kMTEiLCBWYWx1ZXM9bmV3IExpc3Q8aW50PnsxLCAwLCAzLCAxfSwgUHJpY2U9OC4wZn0sCiAgICBuZXcgU3RvY2soKXtOYW1lPSJQcm9kMTEiLCBWYWx1ZXM9bmV3IExpc3Q8aW50PnsxLCAwLCAzLCAxfSwgUHJpY2U9OC4wZn0sCiAgICBuZXcgU3RvY2soKXtOYW1lPSJQcm9kMTgiLCBWYWx1ZXM9bmV3IExpc3Q8aW50PnswLCAwLCA0LCAxfSwgUHJpY2U9NC41Zn0sCiAgICBuZXcgU3RvY2soKXtOYW1lPSJQcm9kMjAiLCBWYWx1ZXM9bmV3IExpc3Q8aW50Pns0LCAwLCAwLCAyfSwgUHJpY2U9OS45Zn0sCiAgICBuZXcgU3RvY2soKXtOYW1lPSJQcm9kMjAiLCBWYWx1ZXM9bmV3IExpc3Q8aW50Pns0LCAwLCAwLCAyfSwgUHJpY2U9OS45Zn0sCiAgICBuZXcgU3RvY2soKXtOYW1lPSJQcm9kMjkiLCBWYWx1ZXM9bmV3IExpc3Q8aW50PnsyLCAxLCAwLCAxfSwgUHJpY2U9Ny4yZn0KfTsKdmFyIHJlcyA9IHN0b2Nrcy5Hcm91cEJ5KHggPT4geCwgKHgsIGcpID0+IG5ldyB7IENvdW50ID0gZy5Db3VudCgpLCBWYWx1ZXMgPSB4fSkuVG9MaXN0KCk7CmZvcmVhY2ggKHZhciBpdGVtIGluIHJlcykgewoJQ29uc29sZS5Xcml0ZUxpbmUoInswfSB7MX0gYXQgezJ9ICh7M30pIiwgaXRlbS5Db3VudCwgaXRlbS5WYWx1ZXMuTmFtZSwgaXRlbS5WYWx1ZXMuUHJpY2UsIHN0cmluZy5Kb2luKCIsICIsIGl0ZW0uVmFsdWVzLlZhbHVlcy5Ub0FycmF5KCkpKTsKfQoJfQp9