【问题标题】:C# how to avoid duplicates in a list?C#如何避免列表中的重复?
【发布时间】:2017-05-19 19:42:04
【问题描述】:

我可以使用什么方法来避免列表中的重复?

一种方法是当我添加一个新项目时,首先检查该元素是否存在,但这使我使用更多代码并迭代所有列表以检查它是否存在。

我可以使用哈希集的另一种方式,如果我尝试添加一个新项目,它本身会检查该项目是否存在,如果不存在,它将添加新项目,如果存在,则什么都不做。

但我知道hashset效率较低,需要比列表更多的资源,所以我不知道使用hashset来避免重复是否是hashset的好用处。

还有其他选择吗?

谢谢。

【问题讨论】:

  • 使用HashSet它不会降低你的性能。检查这个stackoverflow.com/questions/4558754/define-what-is-a-hashset
  • 还有其他选择,但根据您的商品大小,它们可能不合适。 HashSet 更好,因为它可以删除重复项并保证 O(1) AddContains。但您也可以将元素添加到列表中,然后使用 LINQ 使用 Distinct().ToList()。这取决于您的用例。
  • “但我知道哈希集的效率较低” 这是错误的。它不是一个列表,所以它不提供通过索引访问。除此之外,它非常有效
  • But I know that the hashset is less efficient, need more resources than a list。你能提供更多关于那个(例子)的细节吗?
  • 如果您想要一个不允许重复的ICollection<T> 实现,同时仍保留顺序,请考虑使用SortedSet<T> 而不是List<T>

标签: c# list hashset


【解决方案1】:

您可以在一行代码中实现这一点:-

List<long> longs = new List<long> { 1, 2, 3, 4, 3, 2, 5 };

List<long> unique = longs.Distinct().ToList();

unique 将只包含 1,2,3,4,5

【讨论】:

  • 所以您希望每次添加项目时都执行此操作?非常低效
  • @AnandSystematix:如果您事先拥有所有项目,这可能就足够了,但如果列表将按需填写,这是不可行的,这对性能至关重要。 OP希望在添加过程中避免重复,他不想删除重复。
  • @M.kazemAkhgary:嗯,什么时候,每 5 分钟一次?但是,您有一段时间处于不一致的状态。这一点都不好。如果你运气好,客户不会注意到这个错误
  • 我不认为这是对“如何避免列表中的重复”问题的回答。避免集合中的重复项,并从具有重复项的集合中选择独特的项目 - 不同的东西。
  • OP 给出的不使用HashSet 的唯一原因是性能,这比仅使用HashSet 效率低得多。正如其他人所提到的,它也不会“避免”重复。这意味着要有一个持续独特的集合,例如HashSet
【解决方案2】:

您无法避免在 List 中出现重复。没办法 - 没有项目验证。

如果您不关心物品的顺序,请使用HashSet

如果您想保留项目的顺序(实际上有一点歧义 - 项目应该出现在第一次添加的索引还是最后一次添加的索引)。但是您想确保所有项目都是唯一的,那么您应该编写自己的 List 类。 IE。实现IList&lt;T&gt;接口的东西:

public class ListWithoutDuplicates<T> : IList<T>

你在这里有不同的选择。例如。你应该决定什么对你更重要 - 快速添加或内存消耗。因为为了快速添加和包含操作,您应该使用一些基于哈希的数据结构。这是无序的。这是 HashSet 的示例实现,用于存储存储在内部列表中的所有项目的哈希值。您将需要以下字段:

private readonly HashSet<int> hashes = new HashSet<int>();
private readonly List<T> items = new List<T>();
private static readonly Comparer<T> comparer = Comparer<T>.Default;

添加项目很简单(警告:此处和其他地方没有空检查) - 使用项目哈希码快速 O(1) 检查它是否已添加。使用相同的方法删除项目:

public void Add(T item)
{
    var hash = item.GetHashCode();
    if (hashes.Contains(hash))
        return;

    hashes.Add(hash);
    items.Add(item);
}

public bool Remove(T item)
{
    var hash = item.GetHashCode();
    if (!hashes.Contains(hash))
        return false;

    hashes.Remove(item.GetHashCode());
    return items.Remove(item);
}

一些基于索引的操作:

public int IndexOf(T item)
{
    var hash = item.GetHashCode();
    if (!hashes.Contains(hash))
        return -1;

    return items.IndexOf(item);
}

public void Insert(int index, T item)
{
    var itemAtIndex = items[index];
    if (comparer.Compare(item, itemAtIndex) == 0)
        return;

    var hash = item.GetHashCode();

    if (!hashes.Contains(hash))
    {
        hashes.Remove(itemAtIndex.GetHashCode());
        items[index] = item;
        hashes.Add(hash);
        return;
    }

    throw new ArgumentException("Cannot add duplicate item");
}

public void RemoveAt(int index)
{
    var item = items[index];
    hashes.Remove(item.GetHashCode());
    items.RemoveAt(index);
}

还有剩菜:

public T this[int index]
{
    get { return items[index]; }
    set { Insert(index, value); }
}

public int Count => items.Count;
public bool Contains(T item) => hashes.Contains(item.GetHashCode());
public IEnumerator<T> GetEnumerator() => items.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => items.GetEnumerator();

就是这样。现在你有了列表实现,它只会添加一次(第一次)。例如

var list = new ListWithoutDuplicates<int> { 1, 2, 1, 3, 5, 2, 5, 3, 4 };

将创建包含项目 1、2、3、5、4 的列表。注意:如果内存消耗比性能更重要,则不要使用哈希,而是使用 O(n) 的 items.Contains 操作。

顺便说一句,我们刚刚做的实际上是一个 IList Decorator

【讨论】:

    【解决方案3】:

    List 是一个可能包含重复的数据结构。重复元素通过其索引消除歧义。

    一种方法是当我添加一个新项目时,首先检查元素是否存在,但这使我使用更多代码并迭代所有列表以检查它是否存在。

    这是可能的,但容易出错且速度慢。每次要添加元素时,都需要遍历整个列表。您也可能会忘记检查代码中的某处。

    我可以使用哈希集的另一种方式,如果我尝试添加一个新项目,它本身会检查该项目是否存在,如果不存在,它将添加新项目,如果存在,则什么都不做。

    这是首选方式。最好使用标准库来强制执行您想要的约束。

    但我知道hashset效率较低,需要比列表更多的资源,所以我不知道使用hashset来避免重复是否是hashset的一个好用处。

    效率取决于您要做什么;见https://stackoverflow.com/a/23949528/1256041

    还有其他选择吗?

    您可以使用List 实现自己的ISet。这会使插入速度变慢(您需要迭代整个集合),但您将获得O(1) random-access。

    【讨论】:

      【解决方案4】:

      哈希集是检查项目是否存在的最佳方法,因为它是 O(1)。

      因此您可以在列表和哈希集中插入项目 并在插入新项目之前检查它是否存在于哈希集中。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-08
        • 2018-09-30
        • 2015-07-21
        • 1970-01-01
        • 2017-02-05
        • 1970-01-01
        • 1970-01-01
        • 2013-10-08
        相关资源
        最近更新 更多