【问题标题】:How to get duplicate items from a list using LINQ? [duplicate]如何使用 LINQ 从列表中获取重复项? [复制]
【发布时间】:2010-09-28 09:38:57
【问题描述】:

我有一个List<string> 喜欢:

List<String> list = new List<String>{"6","1","2","4","6","5","1"};

我需要将列表中的重复项放入一个新列表中。现在我使用嵌套的for 循环来执行此操作。

生成的list 将包含{"6","1"}

有没有办法使用LINQlambda expressions 来做到这一点?

【问题讨论】:

  • 如果输入是“1”、“1”、“1”,结果列表中应该有多少个元素?
  • @Mark Ba​​yers : 结果列表应该包含"1","1" :-)

标签: c# linq duplicates


【解决方案1】:
var duplicates = lst.GroupBy(s => s)
    .SelectMany(grp => grp.Skip(1));

请注意,这将返回所有重复项,因此如果您只想知道哪些项目在源列表中重复,您可以将Distinct 应用于结果序列或使用the solution given by Mark Byers

【讨论】:

  • lst.GroupBy(s => s.ToUpper()).SelectMany(grp => grp.Skip(1));如果你想做一个不区分大小写的比较:)
  • @JohnJB - GroupBy 的重载允许您提供 IEqualityComparer 而不是使用 ToUpper 进行不区分大小写的比较。
  • Skip(1) 正在跳过第一个项目 :( 你知道如果我想要所有项目应该怎么做吗?
  • @ParPar - this answer 做你想做的事吗?
  • 正如@ScottLangham 指出的那样,这实际上并没有返回所有重复记录,它返回除了每个组中第一次出现的所有重复记录。所以是的,如果你只是在寻找不同重复值的列表,那么这个答案,使用 Distinct 方法是要走的路,但是如果你想要所有重复的行,那么我发现斯科特的答案是要走的路.
【解决方案2】:

这是一种方法:

List<String> duplicates = lst.GroupBy(x => x)
                             .Where(g => g.Count() > 1)
                             .Select(g => g.Key)
                             .ToList();

GroupBy 将相同的元素组合在一起,Where 过滤掉只出现一次的元素,只留下重复的元素。

【讨论】:

  • 不提供所要求的确切结果,但在大多数其他情况下会很有用。
【解决方案3】:

这是另一个选择:

var list = new List<string> { "6", "1", "2", "4", "6", "5", "1" };

var set = new HashSet<string>();
var duplicates = list.Where(x => !set.Add(x));

【讨论】:

  • 我不认为反对者会愿意解释这个答案有什么问题?
  • 哈哈,+1 创新 :) 不仅如此,这正是 OP 想要的。这里的问题是,如果第二次枚举查询,它可能会给出错误的答案(为防止,您必须每次清除集合或初始化一个新集合)。
  • 或者只是在duplicates 构造的末尾拍.ToList()
  • Downvote 不是来自 be,但我真的应该避免在 .Where 中使用副作用,所以这可能是原因。
【解决方案4】:

我知道这不是原始问题的答案,但您可能会发现自己遇到了这个问题。

如果您想要结果中的所有重复项,则可以使用以下方法。

var duplicates = list
    .GroupBy( x => x )               // group matching items
    .Where( g => g.Skip(1).Any() )   // where the group contains more than one item
    .SelectMany( g => g );           // re-expand the groups with more than one item

在我的情况下,我需要所有重复项,以便我可以在 UI 中将它们标记为错误。

【讨论】:

    【解决方案5】:

    我根据@Lee 对 OP 的回复编写了这个扩展方法。 注意,使用了默认参数(需要 C# 4.0)。但是,C# 3.0 中的重载方法调用就足够了。

    /// <summary>
    /// Method that returns all the duplicates (distinct) in the collection.
    /// </summary>
    /// <typeparam name="T">The type of the collection.</typeparam>
    /// <param name="source">The source collection to detect for duplicates</param>
    /// <param name="distinct">Specify <b>true</b> to only return distinct elements.</param>
    /// <returns>A distinct list of duplicates found in the source collection.</returns>
    /// <remarks>This is an extension method to IEnumerable&lt;T&gt;</remarks>
    public static IEnumerable<T> Duplicates<T>
             (this IEnumerable<T> source, bool distinct = true)
    {
         if (source == null)
         {
            throw new ArgumentNullException("source");
         }
    
         // select the elements that are repeated
         IEnumerable<T> result = source.GroupBy(a => a).SelectMany(a => a.Skip(1));
    
         // distinct?
         if (distinct == true)
         {
            // deferred execution helps us here
            result = result.Distinct();
         }
    
         return result;
    }
    

    【讨论】:

      【解决方案6】:
        List<String> list = new List<String> { "6", "1", "2", "4", "6", "5", "1" };
      
          var q = from s in list
                  group s by s into g
                  where g.Count() > 1
                  select g.First();
      
          foreach (var item in q)
          {
              Console.WriteLine(item);
      
          }
      

      【讨论】:

        【解决方案7】:

        希望对你有帮助

        int[] listOfItems = new[] { 4, 2, 3, 1, 6, 4, 3 };
        
        var duplicates = listOfItems 
            .GroupBy(i => i)
            .Where(g => g.Count() > 1)
            .Select(g => g.Key);
        
        foreach (var d in duplicates)
            Console.WriteLine(d);
        

        【讨论】:

          【解决方案8】:

          我试图用一个对象列表来解决同样的问题,但因为我试图将组列表重新打包到原始列表中而遇到了问题。所以我想出循环遍历这些组,用有重复项的项目重新打包原始列表。

          public List<MediaFileInfo> GetDuplicatePictures()
          {
              List<MediaFileInfo> dupes = new List<MediaFileInfo>();
              var grpDupes = from f in _fileRepo
                             group f by f.Length into grps
                             where grps.Count() >1
                             select grps;
              foreach (var item in grpDupes)
              {
                  foreach (var thing in item)
                  {
                      dupes.Add(thing);
                  }
              }
              return dupes;
          }
          

          【讨论】:

            【解决方案9】:

            到目前为止,所有提到的解决方案都执行 GroupBy。即使我只需要第一个 Duplicate 集合的所有元素至少枚举一次。

            一旦发现重复,以下扩展函数就会停止枚举。如果请求下一个副本,它会继续。

            与往常一样,LINQ 有两个版本,一个带有 IEqualityComparer,一个没有。

            public static IEnumerable<TSource> ExtractDuplicates(this IEnumerable<TSource> source)
            {
                return source.ExtractDuplicates(null);
            }
            public static IEnumerable<TSource> ExtractDuplicates(this IEnumerable<TSource source,
                IEqualityComparer<TSource> comparer);
            {
                if (source == null) throw new ArgumentNullException(nameof(source));
                if (comparer == null)
                    comparer = EqualityCompare<TSource>.Default;
            
                HashSet<TSource> foundElements = new HashSet<TSource>(comparer);
                foreach (TSource sourceItem in source)
                {
                    if (!foundElements.Contains(sourceItem))
                    {   // we've not seen this sourceItem before. Add to the foundElements
                        foundElements.Add(sourceItem);
                    }
                    else
                    {   // we've seen this item before. It is a duplicate!
                        yield return sourceItem;
                    }
                }
            }
            

            用法:

            IEnumerable<MyClass> myObjects = ...
            
            // check if has duplicates:
            bool hasDuplicates = myObjects.ExtractDuplicates().Any();
            
            // or find the first three duplicates:
            IEnumerable<MyClass> first3Duplicates = myObjects.ExtractDuplicates().Take(3)
            
            // or find the first 5 duplicates that have a Name = "MyName"
            IEnumerable<MyClass> myNameDuplicates = myObjects.ExtractDuplicates()
                .Where(duplicate => duplicate.Name == "MyName")
                .Take(5);
            

            对于所有这些 linq 语句,只有在找到所请求的项目之前,才会解析集合。序列的其余部分不会被解释。

            恕我直言,这是一个需要考虑的效率提升。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2021-12-16
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-02-28
              • 2021-10-10
              • 2012-05-19
              相关资源
              最近更新 更多