这个linq语句对于从我的newSpecs集合中获取'Name'的唯一值是否正确?
distinctSpecialties显示重复。
IEnumerable<SpecialtyData> distinctSpecialties = newSpecs
.Select(s => s).Distinct()
.OrderBy(s => s.Name);
答案 0 :(得分:4)
您需要定义“distinct” - 默认情况下,如果参考类型是单独的实例(ReferenceEquals),则它们是不同的。您可以通过以下任一方式覆盖默认值:
IEquatable<SpecialtyData>
SpecialtyData
Equals
GetHashCode
和SpecialtyData
IEqualityComparer<SpecialtyData>
并将其传递给Distinct
按名称获取“第一个”不同项目的更简单方法是使用GroupBy
:
IEnumerable<SpecialtyData> distinctSpecialties = newSpecs.GroupBy(s => s.Name)
.Select(g => g.First());
答案 1 :(得分:4)
您要求从我的newSpecs集合中获取“名称”的唯一值,但您的代码会返回IEnumerable<SpecialtyData>
。出了点问题:问题还是返回类型。
如果您只需要名称,则需要IEnumerable<string>
代替:
IEnumerable<string> distinctNames = newSpecs
.Select(s => s.Name)
.Distinct().OrderBy(x => x);
如果您需要整个SpecialtyData
个实例,可以使用GroupBy
+ First
:
IEnumerable<SpecialtyData> distinctSpecialties = newSpecs
.GroupBy(s => s.Name)
.Select(g=> g.First())
或覆盖Equals
类中的GetHashCode
和SpecialtyData
方法,以使Distinct
有效。
答案 2 :(得分:2)
那是因为默认比较是参考比较。它不是在查看数据本身,而是为您提供了不同的参考。您可以使用Select()
获得值得比较的值,或者为您的类型实施IEqualityComparer<T>
并将其传递给Distinct
。
以下是IEqualityComparer<T>
;
class SpecialtyDataEqualityComparer : IEqualityComparer<SpecialtyData>
{
public bool Equals(SpecialtyData lhs, SpecialtyData rhs)
{
return lhs.Name == rhs.Name;
}
public int GetHashCode(SpecialtyData p)
{
return p.Name.GetHashCode();
}
}
如果您执行了.Distinct(new SpecialtyDataEqualitComparer())
,那么您将获得具有不同名称的项目。如果你想要一些其他的相等定义,那么改变Equals
中的逻辑来进行你需要的比较(对GetHashCode
进行相关更改,使它们保持一致,如果你按名称做相等的话就不应该其他一些属性的哈希码。)
答案 3 :(得分:2)
而不是做自定义相等比较器和所有这些,而不是来自MoreLinq的一个非常好的扩展方法 - https://code.google.com/p/morelinq/(作者Jon Skeet)。
下载整个MoreLinq库,或者只需在下面添加以下代码:
public static IEnumerable<TSource> DistinctBy<TSource, TKey>(
this IEnumerable<TSource> source, Func<TSource, TKey> selector)
{
var set = new HashSet<TKey>();
return source.Where(element => set.Add(selector(element)));
}
并像这样使用它:
IEnumerable<SpecialtyData> distinctSpecialties = newSpecs
.Select(s => s).DistinctBy(s => s.Name)
.OrderBy(s => s.Name);
答案 4 :(得分:1)
您可以使用GroupBy
,如下所示
IEnumerable<SpecialtyData> distinctSpecialties =
newSpecs.GroupBy(s => s.Name).Select(g=> g.First()).OrderBy(s => s.Name);
答案 5 :(得分:0)
为了在自定义对象(SpecialtyData)上使用Distinct(),您需要覆盖Distinct()用于确定相等性的两个方法。
public override bool Equals(object other) {
}
public override int GetHashCode() {
}
这两个中的每一个都应返回将SpecialtyData对象定义为唯一的值。在您的情况下,它可能像评估“名称”属性一样简单。
答案 6 :(得分:0)
有一个非常好的post from James Michael Hare解释了为什么你得到这个结果,我会在这里引用它:
要使
Distinct()
(以及许多其他LINQ功能)起作用,这个类就是 比较(在您的示例中为SpecialtyData
)必须实施Equals()
和GetHashCode()
,或者提供单独的IEqualityComparer<T>
作为Distinct()
的参数。许多LINQ方法利用
GetHashCode()
来提高性能 因为在内部,他们会使用像Set<T>
之类的东西来持有 唯一项,使用散列进行O(1)查找。另外,GetHashCode()
可以快速告诉您两个对象是否相同以及哪些对象 绝对不是 - 只要GetHashCode()
得到正确实施 当然。所以你应该在LINQ中创建你想要比较的所有类 实现
Equals()
和GetHashCode()
以获得完整性,或者创建一个 单独IEqualityComparer<T>
实施。