在C#中查找并删除元组列表中的重复项

23

我需要从一个元组列表中找到并移除重复项。基本上,我的数据结构是这样的:

List<Tuple<string, string>> myList = new List<Tuple<string, string>>();

****

private void FillStructure()
{
     myList.Add(Tuple.Create<string, string>("A", "B"));
     myList.Add(Tuple.Create<string, string>("A", "C"));
     myList.Add(Tuple.Create<string, string>("C", "B"));
     myList.Add(Tuple.Create<string, string>("C", "B"));    // Duplicate
     myList.Add(Tuple.Create<string, string>("A", "D"));

     FindAndRemoveDuplicates(myList);
}

private void FindAndRemoveDuplicates(List<Tuple<string, string>> myList)
{
        // how can I perform this ?
}

我不能使用字典,因为我可以有相同的键但不同的值! 预先感谢您。

4个回答

26

您可以使用LINQ的Distinct()方法,如下所示:

myList = myList.Distinct().ToList();

请注意,这将重新创建列表,而不是就地删除重复项。


解决方案非常简单!谢谢! :) - spaghettifunk

6
你可以使用HashSet来实现这个目的 (http://msdn.microsoft.com/en-us/library/bb359438.aspx)
class SameTuplesComparer<T1, T2> : EqualityComparer<Tuple<T1, T2>> 
{
   public override bool Equals(Tuple<T1, T2> t1, Tuple<T1, T2> t2)
   {
      return t1.Item1.Equals(t2.Item1) && t1.Item2.Equals(t2.Item2)
   }


   public override int GetHashCode(Tuple<T1, T2> t)
   {
     return base.GetHashCode();
   }
}

如果您编写自己的比较器,您可以稍微不同地比较字符串(例如,不区分大小写):

class SameStringTuplesComparer: EqualityComparer<Tuple<string, string>> 
{
   public override bool Equals(Tuple<string, string> t1, Tuple<string, string> t2)
   {
      return t1.Item1.Equals(t2.Item1, StringComparison.CurrentCultureIgnoreCase) && t1.Item2.Equals(t2.Item2, StringComparison.CurrentCultureIgnoreCase)
   }


   public override int GetHashCode(Tuple<string, string> t)
   {
     return base.GetHashCode();
   }
}

然后在代码中:

var hashSet = new HashSet<Tuple<string, string>>(list, new SameTuplesComparer());

如果没有自己的比较器:

var hashSet = HashSet<Tuple<string, string>>(list);

现在您可以将元素添加到hashSet中,所有元素都将是唯一的。在添加元素后,您可以将其再次转换为列表:

var uniquedList = hashSet.ToList();

或者只需使用 list.Distinct().ToList()

请注意,在这种情况下,您最终得到的是 HashSet<T> 而不是 List<T>。此外,Tuple<string, string> 不需要提供比较器。 - Adam Houldsworth
1
请注意,base.GetHashCode() 实际上获取的是比较器的哈希码。 - pelican_george

0
使用 distinct() 方法:
myList.Distinct().ToList();

0
如果您想要一个能够就地修改列表的解决方案,您可以使用 HashSet<T>(或对于旧框架,使用 Dictionary<Tuple<string, string>, object> 并忽略值):
var existing = new HashSet<Tuple<string, string>>();

for (int i = myList.Count - 1; i >= 0; i--)
{
    if (existing.Contains(myList[i]))
    {
        myList.RemoveAt(i);
    }
    else
    {
        existing.Add(myList[i]);
    }
}

我们在不使用迭代器的情况下进行倒数计数(否则在迭代时修改列表会导致错误)。

HashSet<T> 还有重载方法可以覆盖相等性,如果需要的话。

个人而言,我会选择 dasblinkenlight's answer 以获得更好的可读性。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接