繁体   English   中英

使用“优先级”从列表中删除重复项

[英]Removing duplicates from a list with “priority”

给出这样的记录集合:

string ID1;
string ID2;
string Data1;
string Data2;
// :
string DataN

最初Data1..N为null,对于这个问题几乎可以忽略。 ID1和ID2都唯一地标识记录。 所有记录都有ID2; 有些还会有ID1。 给定一个ID2,有一个(耗时)方法来获得它的相应ID1。 给定一个ID1,有一个(耗时)方法来获取记录的Data1..N。 我们的最终目标是尽快为所有记录填写Data1..N。

我们的近期目标是(尽可能快地)消除列表中的所有重复项,并保留更多信息。

例如,如果Rec1 == {ID1 =“ABC”,ID2 =“XYZ”},并且Rec2 = {ID1 = null,ID2 =“XYZ”},则这些是重复的,但是我们必须专门删除Rec2并保留Rec1。

最后一个要求消除了删除Dups的标准方法(例如HashSet),因为他们认为“复制”的两面都是可互换的。

如何将原始列表分成3个包含所有数据的列表,包含ID1的列表和只包含ID2的列表。

然后做:

var unique = allData.Concat(id1Data.Except(allData))
                    .Concat(id2Data.Except(id1Data).Except(allData));

在ID2的基础上定义了相等性。

我怀疑有更有效的表达方式,但据我所知,基本的想法是合理的。 将初始列表拆分为三个只是使用GroupBy (然后在每个组上调用ToList以避免重复查询)。

编辑:可能更好的想法:像以前一样分割数据,然后执行:

var result = new HashSet<...>(allData);
result.UnionWith(id1Data);
result.UnionWith(id2Data);

相信 UnionWith保留现有元素而不是用新的但相同的元素覆盖它们。 另一方面,这没有明确规定。 明确定义它会很好...

(同样,要么基于ID2使您的类型实现相等,要么使用相等比较器创建哈希集,这样做。)

几个月前我遇到了类似的问题。

尝试这样的事......

public static List<T> RemoveDuplicateSections<T>(List<T> sections) where T:INamedObject
        {
            Dictionary<string, int> uniqueStore = new Dictionary<string, int>();
            List<T> finalList = new List<T>();
            int i = 0;
            foreach (T currValue in sections)
            {
                if (!uniqueStore.ContainsKey(currValue.Name))
                {
                    uniqueStore.Add(currValue.Name, 0);
                    finalList.Add(sections[i]);
                }
                i++;
             }
            return finalList;
        }

这可能闻起来很多,但我认为如果你确保两个比较的对象出现相同,LINQ-distinct仍然适用于你。 以下比较器会这样做:

private class Comp : IEqualityComparer<Item>
    {
      public bool Equals(Item x, Item y)
      {
        var equalityOfB = x.ID2 == y.ID2;
        if (x.ID1 == y.ID1 && equalityOfB)
          return true;
        if (x.ID1 == null && equalityOfB)
        {
          x.ID1 = y.ID1;
          return true;
        }
        if (y.ID1 == null && equalityOfB)
        {
          y.ID1 = x.ID1;
          return true;
        }
        return false;
      }

      public int GetHashCode(Item obj)
      {
        return obj.ID2.GetHashCode();
      }
    }

然后你可以在列表上使用它......

var l = new[] { 
  new Item { ID1 = "a", ID2 = "b" }, 
  new Item { ID1 = null, ID2 = "b" } };
var l2 = l.Distinct(new Comp()).ToArray();
records.GroupBy(r => r, new RecordByIDsEqualityComparer())
       .Select(g => g.OrderByDescending(r => r, new RecordByFullnessComparer()).First())

或者如果要合并记录,则使用Aggregate而不是OrderByDescending/First

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM