【发布时间】:2014-03-13 08:34:21
【问题描述】:
我正在尝试对复杂类型的集合编写 LINQ 查询。我想针对两个字段的组合在此集合上编写一个不同的查询。
我认为 Lambda 表达式不支持 Distinct(f=>f.propertyname) 的管道。希望它做到了。有人使用了比使用比较器更简单的实现吗?
【问题讨论】:
-
你能发布完整的查询吗?
我正在尝试对复杂类型的集合编写 LINQ 查询。我想针对两个字段的组合在此集合上编写一个不同的查询。
我认为 Lambda 表达式不支持 Distinct(f=>f.propertyname) 的管道。希望它做到了。有人使用了比使用比较器更简单的实现吗?
【问题讨论】:
你可以使用MoreLINQ包中的DistinctBy方法。
var result = items.DistinctBy(f => f.PropertyName);
您可以使用匿名类型 DistinctBy 以获得两列不同的结果。
var result = items.DistinctBy(f => new { f.Property1, f.Property2});
【讨论】:
DISTINCTBY 不是标准的 LINQ 功能
使用纯 LINQ,您可以按所需的所有属性进行分组,然后从每个组中选择第一项:
var result = items.GroupBy(i => new { i.Prop1, i.Prop2 })
.Select(g => g.First());
优点:
缺点:
【讨论】:
你不能像这样使用 distinct。编译器无法知道要采用多个值中的哪一个。您可以使用 GroupBy() 组合它们,也可以根据需要使用 Min()、Max()、First()、Last() 或类似方法从列表中选择一个。
【讨论】:
您有多种选择:
Distinct 的重载实现自定义 IEqualityComparer<T> Equals + GethashCode
另一种(效率较低)不需要创建新类或修改现有类的方法是使用匿名类型的内置GetHashCode+Equals 和Enumerable.GroupBy:
IEnumerable<Complex> distinctObjects =
from c in collection
group c by new { c.Prop1, c.Prop2 } into g
select g.First(); // change logic if you don't want an arbitrary object(first)
这是第二种方法的示例:
public class Complex
{
public string Prop1 { get; set; }
public int Prop2 { get; set; }
public Complex Prop3 { get; set; }
public override bool Equals(object obj)
{
Complex c2 = obj as Complex;
if (obj == null) return false;
return Prop1 == c2.Prop1 && Prop2 == c2.Prop2;
}
public override int GetHashCode()
{
unchecked // Overflow is fine, just wrap
{
int hash = 17;
hash = hash * 23 + Prop1.GetHashCode();
hash = hash * 23 + Prop2;
return hash;
}
}
}
IEqualityComparer 类(1. 方法)的 Equals 和 GethashCode 将是相似的。
【讨论】:
您可以使用您的两个属性动态创建一个匿名类型,然后使用 distinct。
像这样:
[Test]
public void Distinct_with_anonymous_type()
{
var items = new[]
{
new {p1 = 'a', p2 = 2, p3=10}, // double over p1 and p2
new {p1 = 'a', p2 = 3, p3=11},
new {p1 = 'a', p2 = 2, p3=12}, // double over p1 and p2
};
var expected = new[]
{
new {p1 = 'a', p2 = 2},
new {p1 = 'a', p2 = 3},
};
var distinct = items.Select(itm => new { itm.p1, itm.p2 }).Distinct();
Assert.That(distinct, Is.EquivalentTo(expected));
}
希望这会有所帮助!
【讨论】: