LINQ 按总和分组未按预期工作
LINQ group by sum not working as expected
我有这个class:
public class tempClass
{
public int myKey { get; set; }
public int total { get; set; }
}
分组和求和的代码:
var list = new List<tempClass>();
list.Add(new tempClass { myKey = 1, total = 1 });
list.Add(new tempClass { myKey = 1, total = 2 });
list.Add(new tempClass { myKey = 2, total = 3 });
list.Add(new tempClass { myKey = 2, total = 4 });
list = list
.Select(w => new tempClass { myKey = w.myKey, total = w.total })
.GroupBy(x => new tempClass { myKey = x.myKey })
.Select(y => new tempClass { myKey = y.Key.myKey, total = y.Sum(z => z.total) })
.ToList();
list
计数在 GroupBy
之后仍然是 4。
以下代码的相同结果:
list = list
.GroupBy(x => new tempClass { myKey = x.myKey })
.Select(y => new tempClass { myKey = y.Key.myKey, total = y.Sum(z => z.total) })
.ToList();
原因是您按 class 分组,它不会覆盖 Equals
和 GetHashCode
。然后使用 System.Object
的实现,它只比较引用。由于所有都是不同的引用,因此您为每个实例获得一组。
您可以按此 属性 分组或覆盖 Equals
和 GetHashCode
以比较此 属性:
list = list
.Select(w => new tempClass { myKey = w.myKey, total = w.total })
.GroupBy(x => x.myKey)
.Select(y => new tempClass { myKey = y.Key, total = y.Sum(z => z.total) })
.ToList();
不需要两行 Select
行,一行就够了。在 GroupBy
中,只是 select 你的密钥,不要在那里创建你的 class 的新对象:
list = list
.GroupBy(x => x.myKey)
.Select(y => new tempClass { myKey = y.Key, total = y.Sum(z => z.total) })
.ToList();
这是声明式查询语法版本:
list = (from x in list
group x by x.myKey into g
select new tempClass { myKey = g.Key, total = g.Sum(z => z.total) }).ToList();
天哪,您在 LINQ 语句中创建了很多新的 TempClass 对象,是吗?
您没有得到正确结果的原因是您的 GroupBy 没有将具有相等 TempClass.MyKey 的 TempClass 对象分组,但具有相等的 TempClass。
TempClass 的默认 EqualityComparer 声明两个 TempClass 对象相等(如果它们是同一对象),从而使两个 TempClass 对象不相等,即使它们具有相同的值也是如此。
您的查询应该是:
var result = list
.GroupBy(listItem => listItem.MyKey) // make groups with equal MyKey
.Select(group => new // from every group make one new item
{
Key = group.Key, // with key the common MyKey in the group
GrandTotal = group.Sum(groupItem => groupItem.Total);
// and value the sum of all Total values in the group
});
我选择不让最终结果项目成为 TempClass 序列,因为我不确定您是否会将具有此 GrandTotal 的项目视为 TempClass 对象。但是如果你愿意,你可以改变最后的 select:
.Select(group => new TempKey()
{
Key = group.Key,
Total = group.Sum(groupItem => groupItem.Total);
});
我有这个class:
public class tempClass
{
public int myKey { get; set; }
public int total { get; set; }
}
分组和求和的代码:
var list = new List<tempClass>();
list.Add(new tempClass { myKey = 1, total = 1 });
list.Add(new tempClass { myKey = 1, total = 2 });
list.Add(new tempClass { myKey = 2, total = 3 });
list.Add(new tempClass { myKey = 2, total = 4 });
list = list
.Select(w => new tempClass { myKey = w.myKey, total = w.total })
.GroupBy(x => new tempClass { myKey = x.myKey })
.Select(y => new tempClass { myKey = y.Key.myKey, total = y.Sum(z => z.total) })
.ToList();
list
计数在 GroupBy
之后仍然是 4。
以下代码的相同结果:
list = list
.GroupBy(x => new tempClass { myKey = x.myKey })
.Select(y => new tempClass { myKey = y.Key.myKey, total = y.Sum(z => z.total) })
.ToList();
原因是您按 class 分组,它不会覆盖 Equals
和 GetHashCode
。然后使用 System.Object
的实现,它只比较引用。由于所有都是不同的引用,因此您为每个实例获得一组。
您可以按此 属性 分组或覆盖 Equals
和 GetHashCode
以比较此 属性:
list = list
.Select(w => new tempClass { myKey = w.myKey, total = w.total })
.GroupBy(x => x.myKey)
.Select(y => new tempClass { myKey = y.Key, total = y.Sum(z => z.total) })
.ToList();
不需要两行 Select
行,一行就够了。在 GroupBy
中,只是 select 你的密钥,不要在那里创建你的 class 的新对象:
list = list
.GroupBy(x => x.myKey)
.Select(y => new tempClass { myKey = y.Key, total = y.Sum(z => z.total) })
.ToList();
这是声明式查询语法版本:
list = (from x in list
group x by x.myKey into g
select new tempClass { myKey = g.Key, total = g.Sum(z => z.total) }).ToList();
天哪,您在 LINQ 语句中创建了很多新的 TempClass 对象,是吗?
您没有得到正确结果的原因是您的 GroupBy 没有将具有相等 TempClass.MyKey 的 TempClass 对象分组,但具有相等的 TempClass。
TempClass 的默认 EqualityComparer 声明两个 TempClass 对象相等(如果它们是同一对象),从而使两个 TempClass 对象不相等,即使它们具有相同的值也是如此。
您的查询应该是:
var result = list
.GroupBy(listItem => listItem.MyKey) // make groups with equal MyKey
.Select(group => new // from every group make one new item
{
Key = group.Key, // with key the common MyKey in the group
GrandTotal = group.Sum(groupItem => groupItem.Total);
// and value the sum of all Total values in the group
});
我选择不让最终结果项目成为 TempClass 序列,因为我不确定您是否会将具有此 GrandTotal 的项目视为 TempClass 对象。但是如果你愿意,你可以改变最后的 select:
.Select(group => new TempKey()
{
Key = group.Key,
Total = group.Sum(groupItem => groupItem.Total);
});