【问题标题】:Select distinct by two properties in a list选择不同列表中的两个属性
【发布时间】:2012-08-04 18:37:10
【问题描述】:

我有一个list<message>,其中包含GuidDateTime 类型的属性(以及其他属性)。我想删除该列表中GuidDateTime 相同的所有项目(除了一个)。有时这两个属性会与列表中的其他项目相同,但其他属性会有所不同,所以我不能只使用.Distinct()

List<Message> messages = GetList();
//The list now contains many objects, it is ordered by the DateTime property

messages = from p in messages.Distinct(  what goes here? ); 

这是我现在所拥有的,但似乎应该有更好的方法

List<Message> messages = GetList();

for(int i = 0; i < messages.Count() - 1)  //use Messages.Count() -1 because the last one has nothing after it to compare to
{
    if(messages[i].id == messages[i+1}.id && messages[i].date == message[i+1].date)
    {
        messages.RemoveAt(i+1);
    {
    else
    {
         i++
    }
}

【问题讨论】:

  • 谢谢。我不知道为什么我搜索时找不到。
  • 我很高兴乔恩的回答对你有用。请注意:您的“当前使用的方法”无法编译,并且(在修复编译错误之后)它不会在所有情况下都有效 - 根据元素的顺序,您会得到不同的 (错误) 结果(毕竟,您只是在比较相邻的元素)。
  • 感谢您的提醒。 GetList() 返回一个有序列表。我测试了不同的案例,得到了我需要的结果。

标签: c# list distinct linq-to-objects


【解决方案1】:

LINQ to Objects 无法以内置方式轻松提供此功能,但MoreLINQ 有一个方便的DistinctBy 方法:

messages = messages.DistinctBy(m => new { m.id, m.date }).ToList();

【讨论】:

  • @user1304444:这是一个开源库 - 请参阅页面左侧的“Apache License 2.0”链接。
  • 对于其他查看此问题的人来说,上面提到的 Shyju 链接似乎也是一个很好的答案。 stackoverflow.com/questions/489258/…
  • @user1304444:是的,我想是在写这个答案的时候,我决定开始 MoreLINQ :)
  • @PaulZahra:一起。仅当 a.id == b.id &amp;&amp; a.date == b.date 时,两个项目 a 和 b 才会被视为相等。
  • This is now available in .NET 6 无需第三方依赖或自定义扩展方法!
【解决方案2】:

Jon Skeet 的DistinctBy 绝对是您的最佳选择,但是如果您有兴趣定义自己的扩展方法,您可能会喜欢这个更简洁的版本:

public static IEnumerable<TSource> DistinctBy<TSource, TKey>
(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
    var known = new HashSet<TKey>();
    return source.Where(element => known.Add(keySelector(element)));
}

签名相同:

messages = messages.DistinctBy(x => new { x.id, x.date }).ToList();

【讨论】:

  • 我知道这是旧的,但请注意,您必须在致电DistinctBy() 后致电ToList()ToArray()。如果您直接在IEnumerable 上工作并多次枚举它将不起作用,因为这些项目在第一次通过IEnumerable 时被添加到HashSet 并且不会第二次返回,如.NET Fiddle所示。
【解决方案3】:

试试这个,

 var messages = (from g1 in messages.GroupBy(s => s.id) from g2 in g1.GroupBy(s => s.date) select g2.First()).ToList();

【讨论】:

    【解决方案4】:

    您可以查看我的 PowerfulExtensions 库。目前它还处于非常年轻的阶段,但您已经可以在任意数量的属性上使用 Distinct、Union、Intersect、Except 等方法;

    这是你使用它的方式:

    using PowerfulExtensions.Linq;
    ...
    var distinct = myArray.Distinct(x => x.A, x => x.B);
    

    【讨论】:

      【解决方案5】:

      这个呢?

      var messages = messages
                     .GroupBy(m => m.id)
                     .GroupBy(m => m.date)
                     .Select(m => m.First());
      

      【讨论】:

      • 不编译...记住 GroupBy 返回一个IGrouping
      • 如果 HashSet 在您正在开发的平台上不可用,如 silverslight ....,则此方法有效
      猜你喜欢
      • 2016-05-14
      • 1970-01-01
      • 2012-03-03
      • 1970-01-01
      • 1970-01-01
      • 2017-01-26
      • 1970-01-01
      • 1970-01-01
      • 2017-11-11
      相关资源
      最近更新 更多