I have some problems in executing a Linq query with the group by clause in a C# project as follows:
public class Stock {
public string Name {get; set;}
public List<int> Values {get; set;}
public float Price {get; set;}
}
// Stock collection
List<Stock> 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 query = stocks.GroupBy(x => x, (x, g) => new { Count = g.Count(), Values = x}).ToList();
This query gives wrong grouping results.
In order for GroupBy
to produce a grouping, the object by which you group must have an override of GetHashCode
and Equals
, or you need to provide a suitable equality comparer to GroupBy
.
Your Stock
does not override GetHashCode
/Equals
, and your GroupBy
query does not use a custom equality comparer, so you get unexpected results.
Providing suitable overrides will fix this problem:
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();
}
}