Distinct 不适用于 LINQ to Objects
class Program
{
static void Main(string[] args)
{
List<Book> books = new List<Book>
{
new Book
{
Name="C# in Depth",
Authors = new List<Author>
{
new Author
{
FirstName = "Jon", LastName="Skeet"
},
new Author
{
FirstName = "Jon", LastName="Skeet"
},
}
},
new Book
{
Name="LINQ in Action",
Authors = new List<Author>
{
new Author
{
FirstName = "Fabrice", LastName="Marguerie"
},
new Author
{
FirstName = "Steve", LastName="Eichert"
},
new Author
{
FirstName = "Jim", LastName="Wooley"
},
}
},
};
var temp = books.SelectMany(book => book.Authors).Distinct();
foreach (var author in temp)
{
Console.WriteLine(author.FirstName + " " + author.LastName);
}
Console.Read();
}
}
public class Book
{
public string Name { get; set; }
public List<Author> Authors { get; set; }
}
public class Author
{
public string FirstName { get; set; }
public string LastName { get; set; }
public override bool Equals(object obj)
{
return true;
//if (obj.GetType() != typeof(Author)) return false;
//else return ((Author)obj).FirstName == this.FirstName && ((Author)obj).FirstName == this.LastName;
}
}
这是基于“LINQ in Action”中的示例。清单 4.16。
这会打印 Jon Skeet 两次。为什么?我什至尝试过重写 Author 类中的 Equals 方法。 Still Distinct 似乎不起作用。我缺少什么?
编辑: 我也添加了 == 和 != 运算符重载。仍然没有帮助。
public static bool operator ==(Author a, Author b)
{
return true;
}
public static bool operator !=(Author a, Author b)
{
return false;
}
class Program
{
static void Main(string[] args)
{
List<Book> books = new List<Book>
{
new Book
{
Name="C# in Depth",
Authors = new List<Author>
{
new Author
{
FirstName = "Jon", LastName="Skeet"
},
new Author
{
FirstName = "Jon", LastName="Skeet"
},
}
},
new Book
{
Name="LINQ in Action",
Authors = new List<Author>
{
new Author
{
FirstName = "Fabrice", LastName="Marguerie"
},
new Author
{
FirstName = "Steve", LastName="Eichert"
},
new Author
{
FirstName = "Jim", LastName="Wooley"
},
}
},
};
var temp = books.SelectMany(book => book.Authors).Distinct();
foreach (var author in temp)
{
Console.WriteLine(author.FirstName + " " + author.LastName);
}
Console.Read();
}
}
public class Book
{
public string Name { get; set; }
public List<Author> Authors { get; set; }
}
public class Author
{
public string FirstName { get; set; }
public string LastName { get; set; }
public override bool Equals(object obj)
{
return true;
//if (obj.GetType() != typeof(Author)) return false;
//else return ((Author)obj).FirstName == this.FirstName && ((Author)obj).FirstName == this.LastName;
}
}
This is based on an example in "LINQ in Action". Listing 4.16.
This prints Jon Skeet twice. Why? I have even tried overriding Equals method in Author class. Still Distinct does not seem to work. What am I missing?
Edit:
I have added == and != operator overload too. Still no help.
public static bool operator ==(Author a, Author b)
{
return true;
}
public static bool operator !=(Author a, Author b)
{
return false;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
当涉及到自定义对象时,LINQ Distinct 并不那么聪明。
它所做的只是查看您的列表并查看它有两个不同的对象(它不关心它们的成员字段是否具有相同的值)。
一种解决方法是实现 IEquatable 接口,如此处所示。
如果你像这样修改你的 Author 类,它应该可以工作。
尝试使用 DotNetFiddle
LINQ Distinct is not that smart when it comes to custom objects.
All it does is look at your list and see that it has two different objects (it doesn't care that they have the same values for the member fields).
One workaround is to implement the IEquatable interface as shown here.
If you modify your Author class like so it should work.
Try it as DotNetFiddle
Distinct()
方法检查引用类型的引用相等性。这意味着它正在寻找字面上相同的重复对象,而不是包含相同值的不同对象。有一个重载,它需要一个IEqualityComparer,因此您可以指定不同的逻辑来确定给定对象是否等于另一个对象。
如果您希望 Author 通常表现得像普通对象(即仅引用相等性),但为了通过名称值进行区分检查相等性,请使用 IEqualityComparer。如果您始终希望根据名称值比较 Author 对象,请重写 GetHashCode 和 Equals,或实现 IEquatable。
IEqualityComparer
接口上的两个成员是Equals
和GetHashCode
。确定两个Author
对象是否相等的逻辑似乎是“名字”和“姓氏”字符串是否相同。The
Distinct()
method checks reference equality for reference types. This means it is looking for literally the same object duplicated, not different objects which contain the same values.There is an overload which takes an IEqualityComparer, so you can specify different logic for determining whether a given object equals another.
If you want Author to normally behave like a normal object (i.e. only reference equality), but for the purposes of Distinct check equality by name values, use an IEqualityComparer. If you always want Author objects to be compared based on the name values, then override GetHashCode and Equals, or implement IEquatable.
The two members on the
IEqualityComparer
interface areEquals
andGetHashCode
. Your logic for determining whether twoAuthor
objects are equal appears to be if the First and Last name strings are the same.不实现
IEquatable
、Equals
和GetHashCode
的另一种解决方案是使用 LINQsGroupBy
方法并选择第一项来自 IGrouping。Another solution without implementing
IEquatable
,Equals
andGetHashCode
is to use the LINQsGroupBy
method and to select the first item from the IGrouping.还有另一种方法可以从用户定义的数据类型列表中获取不同的值:
当然,它会给出不同的数据集
There is one more way to get distinct values from list of user defined data type:
Surely, it will give distinct set of data
Distinct()
对可枚举对象执行默认的相等比较。如果您尚未覆盖Equals()
和GetHashCode()
,然后它使用object
上的默认实现来比较引用。简单的解决方案是添加
Equals()
和GetHashCode()
到参与您正在比较的对象图的所有类(即 Book 和 Author)。IEqualityComparer
界面非常方便,允许您实施Equals()
< /a> 和GetHashCode()
< /a> 在单独的类中,当您无法访问需要比较的类的内部结构,或者您正在使用不同的比较方法时。Distinct()
performs the default equality comparison on objects in the enumerable. If you have not overriddenEquals()
andGetHashCode()
, then it uses the default implementation onobject
, which compares references.The simple solution is to add a correct implementation of
Equals()
andGetHashCode()
to all classes which participate in the object graph you are comparing (ie Book and Author).The
IEqualityComparer
interface is a convenience that allows you to implementEquals()
andGetHashCode()
in a separate class when you don't have access to the internals of the classes you need to compare, or if you are using a different method of comparison.您已经重写了 Equals(),但请确保您也重写了 GetHashCode()
You've overriden Equals(), but make sure you also override GetHashCode()
上面的答案都是错误的!!!
正如 MSDN 上所述,Distinct 返回默认的 Equator,如所述,Default 属性检查类型 T 是否实现 System.IEquatable 接口,如果是,则返回使用该实现的 EqualityComparer。 否则,它会返回一个 EqualityComparer,该 EqualityComparer 使用 T 提供的 Object.Equals 和 Object.GetHashCode 的重写,
这意味着只要重写 Equals 就可以了。
您的代码不起作用的原因是您检查名字==姓氏。
请参阅 https://msdn.microsoft.com/library/bb348436(v =vs.100).aspx 和 https://msdn.microsoft.com/en-us/library/ms224763(v=vs.100).aspx
The Above answers are wrong!!!
Distinct as stated on MSDN returns the default Equator which as stated The Default property checks whether type T implements the System.IEquatable interface and, if so, returns an EqualityComparer that uses that implementation. Otherwise, it returns an EqualityComparer that uses the overrides of Object.Equals and Object.GetHashCode provided by T
Which means as long as you overide Equals you are fine.
The reason you're code is not working is because you check firstname==lastname.
see https://msdn.microsoft.com/library/bb348436(v=vs.100).aspx and https://msdn.microsoft.com/en-us/library/ms224763(v=vs.100).aspx
而不是
做
Instead of
Do
您可以通过多种方式实现此目的:
1.您可以实现 IEquatable 接口,如下所示Enumerable.Distinct 方法 或者您可以查看 @skalb 在这篇文章中的回答
2. 如果您的对象没有唯一键,您可以使用 GroupBy 方法来获得不同的对象列表,您必须对对象的所有属性,然后选择第一个对象。
例如如下所示并为我工作:
MyObject 类如下所示:
3. 如果您的对象具有唯一键,则只能在分组依据中使用它。
例如,我的对象的唯一键是 Id。
You can achieve this several ways:
1. You may to implement the IEquatable interface as shown Enumerable.Distinct Method or you can see @skalb's answer at this post
2. If your object has not unique key, You can use GroupBy method for achive distinct object list, that you must group object's all properties and after select first object.
For example like as below and working for me:
MyObject class is like as below:
3. If your object's has unique key, you can only use the it in group by.
For example my object's unique key is Id.
您可以在列表上使用扩展方法,该方法根据计算的哈希检查唯一性。
您还可以更改扩展方法以支持 IEnumerable。
示例:
扩展方法:
You can use extension method on list which checks uniqueness based on computed Hash.
You can also change extension method to support IEnumerable.
Example:
Extension Method:
下面代码中的等于运算符不正确。
旧
新
The Equal operator in below code is incorrect.
Old
NEW