【问题标题】:Test if all values in a list are unique测试列表中的所有值是否都是唯一的
【发布时间】:2013-08-20 15:58:03
【问题描述】:

我有一个小字节列表,我想测试它们是否都是不同的值。 例如,我有这个:

List<byte> theList = new List<byte> { 1,4,3,6,1 };

检查所有值是否不同的最佳方法是什么?

【问题讨论】:

  • 因为这是一个典型的课堂问题,所以我会回答一个问题。如果是排序的,你会怎么做?

标签: c#


【解决方案1】:
bool isUnique = theList.Distinct().Count() == theList.Count();

【讨论】:

  • 只是好奇:这对空间和时间有什么要求?
  • @dtb should be about O(N)。当然,考虑到这是一个“小列表”,几乎任何算法都将是闪电般的速度。 IMO 这在可读性和简洁性方面获胜,而且由于速度不是问题,这使它变得完美。
  • 这比它可能的效率低
  • @Tim Schmelter 的答案在使用 HashSet 时快了 4 倍。这种方法适合日常使用,但对于像数百万这样的较大集合,应该使用 HashSet。
【解决方案2】:

这是另一种比Enumerable.Distinct + Enumerable.Count 更有效的方法(如果序列不是集合类型则更有效)。它使用HashSet&lt;T&gt; 消除重复,查找效率非常高,并且具有计数属性:

var distinctBytes = new HashSet<byte>(theList);
bool allDifferent = distinctBytes.Count == theList.Count;

或另一种 - 更微妙和有效的 - 方法:

var diffChecker = new HashSet<byte>();
bool allDifferent = theList.All(diffChecker.Add);

HashSet&lt;T&gt;.Add 返回false,如果该元素已经在HashSet 中,则无法添加。 Enumerable.All 在第一个“false”处停止。

【讨论】:

  • 如此简单明了,我为什么不先考虑一下 :) 我在单元测试中使用了这个单行代码,以确认由我的出色代码生成的 1000 万个元素确实是独一无二的 Assert.IsTrue(samples.Add(AwesomeClass.GetUnique()));。他们过去和现在都是 :) 为你 +1 蒂姆 :)
  • 我已经尝试过你对这个问题的回答,但它不起作用先生:stackoverflow.com/questions/34941162/…
  • 应该是这个:bool allDifferent = theList.All(s =&gt; diffChecker.Add(s))
  • 不,不需要。在这种情况下,您可以直接传递委托
  • @AndréReichelt - 我刚刚打开了您的代码,第三种情况 (List.All(HashSet.Add)) 似乎在几乎所有情况下都比其他两种情况快得多
【解决方案3】:

好的,这是我能想到的使用标准 .Net 最有效的方法

using System;
using System.Collections.Generic;

public static class Extension
{
    public static bool HasDuplicate<T>(
        this IEnumerable<T> source,
        out T firstDuplicate)
    {
        if (source == null)
        {
            throw new ArgumentNullException(nameof(source));
        }

        var checkBuffer = new HashSet<T>();
        foreach (var t in source)
        {
            if (checkBuffer.Add(t))
            {
                continue;
            }

            firstDuplicate = t;
            return true;
        }

        firstDuplicate = default(T);
        return false;
    }
}

本质上,如果您只想找到第一个重复项,那么枚举整个序列两次有什么意义。

我可以通过特殊封装一个空的单元素序列来进一步优化这一点,但这会以最小的增益降低可读性/可维护性。

【讨论】:

  • 很好地添加了一个重复值输出,对验证非常有用
  • 我在这里测试了 3 个解决方案,这确实是这个页面上最有效的。不过里面有一些错别字(例如sequence 应该是source)。但是一旦这些问题得到解决,效果就会很好
  • @mikenelson,应该会更好
  • 为了可读性,我认为循环中应该是if (!checkBuffer.Add(t)) { firstDuplicate = t; return true }
【解决方案4】:

使用GroupByDistinct类似的逻辑:

var isUnique = theList.GroupBy(i => i).Count() == theList.Count;

【讨论】:

  • 如果您想检查属性 theList.GroupBy(o =&gt; o.SomeProperty).Count() == theList.Count; 的唯一性,而 Distinct() 不允许这样做,这很有用。
【解决方案5】:

也可以这样做:使用哈希集

var uniqueIds = new HashSet<long>(originalList.Select(item => item.Id));

            if (uniqueIds.Count != originalList.Count)
            {
            }

【讨论】:

    【解决方案6】:

    有很多解决方案。

    毫无疑问,使用 LINQ 的“juergen d”和“Tim Schmelter”更漂亮。

    但是,如果您只考虑“复杂性”和速度,最好的解决方案就是自己实施。 解决方案之一是创建一个 N 大小的数组(字节为 256)。 并循环数组,并且在每次迭代中,如果值为 1,则测试匹配的数字索引,这意味着我已经增加了数组索引,因此数组不是不同的,否则我将增加数组单元格并继续检查.

    【讨论】:

    • 您可以使用 256 位 = 32 字节 = 8 个整数的位向量。但是您的 Big O = O(n) 仍然与使用另一个答案中提出的 Hashet 相同。
    • 这是 O(n) 所以可能是最快的,(测试一下)。边走边检查或最后检查是最快的吗?我怀疑最终会改善最坏的情况,但随着您的发展,可能会改善平均和最佳情况)。如果没有重复,这将是最坏情况下的性能。同样,对于更大的数据类型,这将无法正常工作,对于 16 位类型,您将不得不使用 64k 的计数,以及 64k 位(8k 字节),但对于任何更大的内存使用将开始变得愚蠢。但是,我喜欢 8 位值的这个答案。
    • @TamusJRoyce 如果你想存储 4294967296 种可能性,你需要 4GB 而不是 42MB(或者 512MB 使用位掩码)
    • 不知道我在想什么。 “分配 42MB+ 的内存来保存所有 4294967296 种可能性。并使用简单的桶计数器。或者甚至使用位掩码 xor 并检查是否有任何位从 true 更改为 false。42MB+ / 8 = 5MB+ 对于今天的硬件来说,开销似乎太大了。但是有朝一日,这可能是有价值的。”并不是真正的相关评论。哈希集是最好的。如果您正在处理非常大的数组,您需要非常大的内存。但在这种奇怪的边缘情况下,使用 CRC 算法的 Heristic 会更好。将其映射到多项式。如果接近,请评估。谢谢@tigrou!
    【解决方案7】:

    如果您想查找重复值,还有另一种解决方案。

    var values = new [] { 9, 7, 2, 6, 7, 3, 8, 2 };
    
    var sorted = values.ToList();
    sorted.Sort();
    for (var index = 1; index < sorted.Count; index++)
    {
        var previous = sorted[index - 1];
        var current = sorted[index];
        if (current == previous)
            Console.WriteLine(string.Format("duplicated value: {0}", current));
    }
    

    输出:

    duplicated value: 2
    duplicated value: 7
    

    http://rextester.com/SIDG48202

    【讨论】:

      【解决方案8】:

      我检查一个 IEnumerable (aray, list, etc) 是否像这样是唯一的:

      var isUnique = someObjectsEnum.GroupBy(o => o.SomeProperty).Max(g => g.Count()) == 1;
      

      【讨论】:

        猜你喜欢
        • 2020-07-11
        • 2012-03-09
        • 1970-01-01
        • 2011-07-13
        • 1970-01-01
        • 2013-07-17
        • 1970-01-01
        • 1970-01-01
        • 2016-01-13
        相关资源
        最近更新 更多