【问题标题】:LINQ: Enumerate through duplicates in List and remove themLINQ:枚举列表中的重复项并删除它们
【发布时间】:2015-08-03 15:04:20
【问题描述】:

我需要删除重复项,还要记录我要删除的内容。我现在有两种解决方案,一种可以遍历每个重复项,另一种可以删除重复项。我知道在 foreach 中就地删除是危险的,所以我有点坚持如何尽可能高效地做到这一点。

我现在得到了什么

var duplicates = ListOfThings
.GroupBy(x => x.ID)
.Where(g => g.Skip(1).Any())
.SelectMany(g => g);

foreach (var duplicate in duplicates)
{
    Log.Append(Logger.Type.Error, "Conflicts with another", "N/A", duplicate.ID);
}


ListOfThings = ListOfThings.GroupBy(x => x.ID).Select(y => y.First()).ToList();

【问题讨论】:

  • 也许这个链接对你有帮助:blogs.msdn.com/b/bclteam/archive/2006/11/09/…
  • 试试:var duplicateItems = list.GroupBy(x => x.ID).Where(x => x.Count() > 1).Select(x => x.Key);
  • @jacoblam 这如何让我报告错误并同时删除它们?
  • 这些只是重复的,因此您可以在foreach 循环中报告它们。删除它们可以以不同的方式完成,我在下面的答案中建议了一个哈希集,并且可以提供详细信息。

标签: c# linq list duplicates


【解决方案1】:

好吧,ToList()实现查询,所以如果您允许副作用(即写入日志),它可能是这样的:

var cleared = ListOfThings
  .GroupBy(x => x.ID)
  .Select(chunk => {
     // Side effect: writing to log while selecting
     if (chunk.Skip(1).Any()) 
       Log.Append(Logger.Type.Error, "Conflicts with another", "N/A", chunk.Key);
     // if there're duplicates by Id take the 1st one
     return chunk.First();
   })
  .ToList();

【讨论】:

  • 我相信这可能是性能最好的方式,这就是我所要求的。值得注意的是,它有点复杂,性能提升可能不值得混淆。尽管如此,你还是按照被问到的方式回答问题
  • if (chunk.Skip(1).Any() > 1) 应该是if (chunk.Skip(1).Any())
【解决方案2】:

当可以使用Aggregate 函数来确定报告和结果的重复项时,为什么要分组?

示例

var items = new List<string>() { "Alpha", "Alpha", "Beta", "Gamma", "Alpha"};

var duplicatesDictionary = 
     items.Aggregate (new Dictionary<string, int>(),  
                      (results, itm) => 
                                       {
                                         if (results.ContainsKey(itm))
                                            results[itm]++;
                                         else
                                           results.Add(itm, 1);

                                         return results;
                                  });

这是上面计算和报告每个插入的结果。

现在提取大于 1 的任何计数的重复报告。

duplicatesDictionary.Where (kvp => kvp.Value > 1)
         .Select (kvp => string.Format("{0} had {1} duplicates", kvp.Key, kvp.Value))

现在最终的结果就是提取所有的键。

 duplicatesDictionary.Select (kvp => kvp.Key);

【讨论】:

    【解决方案3】:

    您可以使用哈希集并将其与列表联合以获取唯一项;只需覆盖参考比较。实现IEqualityComparer&lt;T&gt;很灵活;如果只是 ID 使两个对象唯一,那么可以;但如果它更多,你也可以扩展它。

    您可以使用 LINQ 获取重复项。

    void Main()
    {
        //your original class:
        List<Things> originalList = new List<Things> { new Things(5), new Things(3), new Things(5) };
        //i'm doing this in LINQPad; if you're using VS you may need to foreach the object
        Console.WriteLine(originalList);
        //put your duplicates back in a list and log them as you did.
        var duplicateItems = originalList.GroupBy(x => x.ID).Where(x => x.Count() > 1).ToList();//.Select(x => x.GetHashCode());
        Console.WriteLine(duplicateItems);
        //create a custom comparer to compare your list; if you care about more than ID then you can extend this
        var tec = new ThingsEqualityComparer();
        var listThings = new HashSet<Things>(tec);
        listThings.UnionWith(originalList);
        Console.WriteLine(listThings);
    }
    
    // Define other methods and classes here
    public class Things 
    {
        public int ID {get;set;}
    
        public Things(int id)
        {
            ID = id;
        }
    }
    
    public class ThingsEqualityComparer : IEqualityComparer<Things>
    {
        public bool Equals(Things thing1, Things thing2)
        {
            if (thing1.ID == thing2.ID)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    
        public int GetHashCode(Things thing)
        {
            int hCode = thing.ID;
            return hCode.GetHashCode();
        }
    }
    

    【讨论】:

    • 您可以在 Select() 之后调用 Distinct(),而不是使用哈希集。
    • 是的,我可以毫无问题地获得重复项,它可以先枚举它们然后删除它们。
    猜你喜欢
    • 2010-11-26
    • 2022-01-23
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    • 2020-08-04
    • 1970-01-01
    相关资源
    最近更新 更多