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

时间:2009-11-05 22:01:23

标签: c# .net algorithm list distinct

给出这样的记录集合:

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)的标准方法,因为他们认为“复制”的两面都可以互换。

4 个答案:

答案 0 :(得分:4)

如何将原始列表分成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使你的类型实现相等,要么使用相等比较器来创建哈希集。)

答案 1 :(得分:0)

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

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

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;
        }

答案 2 :(得分:0)

这可能闻起来很多,但我认为如果确保两个比较的对象出现相同,那么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();

答案 3 :(得分:0)

records.GroupBy(r => r, new RecordByIDsEqualityComparer())
       .Select(g => g.OrderByDescending(r => r, new RecordByFullnessComparer()).First())

或者如果要合并记录,则Aggregate代替OrderByDescending/First