避免在C#中向列表(List)中添加重复元素

46
string[] lines3 = new string[100];
List<string> lines2 = new List<string>();
lines3 = Regex.Split(s1, @"\s*,\s*");

if (!lines2.Contains(lines3.ToString()))
{
    lines2.AddRange(lines3.Distinct().ToArray());
}

我已经检查了所有空格等,但是在我的List中仍然会出现重复的值。

我必须在这里删除我的重复值。


lines2 是字符串列表,抱歉在复制和粘贴代码时出现了小错误。 - vini
两个字符串之间可以有空格,例如=sbc bgp - vini
2
你是否考虑过在这种情况下使用 HashSet<String> 而不是 List<String>,它的性能会更好。 - bashmohandes
11个回答

71
您可以使用Enumerable.Except从lines3中获取不在lines2中的唯一项:
lines2.AddRange(lines3.Except(lines2));

如果lines2包含了lines3中的所有项,则不会添加任何内容。顺便说一句,内部使用Set<string>来获取第二个序列中的唯一项并验证这些项是否存在于第一个序列中。因此,它非常快。


2
这是一个不错的解决方案,而且速度非常快。但是,在处理数百万条记录时,你需要考虑使用其他方法,例如HasSet、Dictionary或类似的东西。只是提前告诉你,从吃过亏的经验学到了教训 ;) - Squazz

48

您的这次检查:

if (!lines2.Contains(lines3.ToString()))

无效。你在检查你的lines2是否包含System.String[],因为lines3.ToString()将给你这个。你需要检查lines3中的项是否存在于lines2中。

你可以迭代lines3中的每个项,检查它是否存在于lines2中,然后添加它。就像这样:

foreach (string str in lines3)
{
    if (!lines2.Contains(str))
        lines2.Add(str);
}

如果你的lines2是一个空列表,那么你可以像这样将lines3中不同的值简单地添加到该列表中:

lines2.AddRange(lines3.Distinct());

那么你的lines2将包含不同的值。


42

使用 HashSet<string> 而不是 List<string>。它可以提供更好的性能,因为您不需要为任何项提供检查。集合会为您管理。这就是列表和集合之间的区别。例如:

HashSet<string> set = new HashSet<string>();

set.Add("a");
set.Add("a");
set.Add("b");
set.Add("c");
set.Add("b");
set.Add("c");
set.Add("a");
set.Add("d");
set.Add("e");
set.Add("e");

var total = set.Count;

总数为5,值为abcde

List<T>的实现并不直接提供此功能。您可以自己实现,但需要提供此控件。例如,使用此扩展方法

public static class CollectionExtensions
{
    public static void AddItem<T>(this List<T> list, T item)
    {
       if (!list.Contains(item))
       {
          list.Add(item);
       }
    }
}

并使用它:

var list = new List<string>();
list.AddItem(1);
list.AddItem(2);
list.AddItem(3);
list.AddItem(2);
list.AddItem(4);
list.AddItem(5);

9
记住,HashSet 是无序的,这意味着它不会保留添加项目的顺序。如果需要保留特定的顺序,HashSet 将无法满足要求。 - Doug S

4
你可以使用简单的Union + Distinct
var lines = lines2.Union(lines3).Distinct();

这将把第二个列表中的所有项目添加到第一个列表中,然后返回合并列表中所有唯一的字符串。对于大型列表可能性能不佳,但它很简单。

参考资料:http://msdn.microsoft.com/en-us/library/bb341731.aspx


4
如果你不想在列表中出现重复项,可以使用 HashSet。这样其他人阅读你的代码时就能清楚地了解你的意图,而且你需要编写的代码量更少,因为 HashSet 已经处理了你要做的事情。

7
考虑使用 HashSet 的人请注意,不能保证元素的顺序。 - BenKoshy

2
如果您的检查有效,它要么会添加所有项目,要么将不添加任何项目。但是,在数组上调用ToString方法会返回数据类型的名称,而不是数组的内容。而且Contains方法只能查找单个项目,无法查找多个项目的集合。您必须检查数组中的每个字符串:
string[] lines3;
List<string> lines2 = new List<string>();

lines3 = Regex.Split(s1, @"\s*,\s*");

foreach (string s in lines3) {
  if (!lines2.Contains(s)) {
    lines2.Add(s);
  }
}

但如果你从一个空列表开始,你可以使用Distinct方法来删除重复项,只需要一行代码:

List<string> lines2 = Regex.Split(s1, @"\s*,\s*").Distinct().ToList();

2
如果您想将不同的值保存到集合中,可以尝试使用 HashSet Class。它会自动删除重复的值,节省您的编码时间。 :)

1

1
使用一个HashSet和你的List:
List<string> myList = new List<string>();
HashSet<string> myHashSet = new HashSet<string>();

public void addToList(string s) {
    if (myHashSet.Add(s)) {
        myList.Add(s);
    }
}

如果smyHashSet中不存在,myHashSet.Add(s)将返回true

缺点是你不能在HashSet上使用索引。 - Tiffany

0

受 #Felipe Oriani 的启发,我制作了这个扩展程序,并愿意在此分享。

public static class CollectionExtension
{
    public static void AddUniqueItem<T>(this List<T> list, T item, bool throwException)
    {
        if (!list.Contains(item))
        {
            list.Add(item);
        }
        else if(throwException)
        {
            throw new InvalidOperationException("Item already exists in the list");
        }
    }
    public static bool IsUnique<T>(this List<T> list, IEqualityComparer<T> comparer)
    {
        return list.Count == list.Distinct(comparer).Count();
    }
    public static bool IsUnique<T>(this List<T> list)
    {
        return list.Count == list.Distinct().Count();
    }
}

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