LINQ:枚举List中的重复项并删除它们

时间:2015-08-03 15:04:21

标签: c# linq list duplicates

我需要删除重复项,还要记录我要删除的内容。我现在有两个解决方案,一个可以查看每个副本,另一个可以删除重复项。我知道在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();

3 个答案:

答案 0 :(得分:2)

好吧,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();

答案 1 :(得分:0)

您可以使用哈希集并将其与列表结合以获取唯一项;只是覆盖参考比较。实施IEqualityComparer<T>是灵活的;如果它只是使两个对象唯一的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();
    }
}

答案 2 :(得分:0)

为什么分组可以使用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;
                                  });

以上是上述结果,其中每个插入物都被计算并报告。

enter image description here

现在为1以上的任何计数提取重复报告。

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

enter image description here

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

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

enter image description here