测试列表中的所有值是不是都是唯一的
Posted
技术标签:
【中文标题】测试列表中的所有值是不是都是唯一的【英文标题】: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 ;
检查所有值是否不同的最佳方法是什么?
【问题讨论】:
因为这是一个典型的课堂问题,所以我会回答一个问题。如果是排序的,你会怎么做? 【参考方案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<T>
消除重复,查找效率非常高,并且具有计数属性:
var distinctBytes = new HashSet<byte>(theList);
bool allDifferent = distinctBytes.Count == theList.Count;
或另一种 - 更微妙和有效的 - 方法:
var diffChecker = new HashSet<byte>();
bool allDifferent = theList.All(diffChecker.Add);
HashSet<T>.Add
返回false
,如果该元素已经在HashSet
中,则无法添加。 Enumerable.All
在第一个“false”处停止。
【讨论】:
如此简单明了,我为什么不先考虑一下 :) 我在单元测试中使用了这个单行代码,以确认由我的出色代码生成的 1000 万个元素确实是独一无二的Assert.IsTrue(samples.Add(AwesomeClass.GetUnique()));
。他们过去和现在都是 :) 为你 +1 蒂姆 :)
我已经尝试过你对这个问题的回答,但它不起作用先生:***.com/questions/34941162/…
应该是这个:bool allDifferent = theList.All(s => 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】:
使用GroupBy
与Distinct
类似的逻辑:
var isUnique = theList.GroupBy(i => i).Count() == theList.Count;
【讨论】:
如果您想检查属性theList.GroupBy(o => 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;
【讨论】:
以上是关于测试列表中的所有值是不是都是唯一的的主要内容,如果未能解决你的问题,请参考以下文章
python函数定义来查找列表中的所有值是不是都是奇数或都不是[关闭]
我正在尝试创建一个函数来检查字符串中的所有字符是不是都是唯一的,如果是这样,则返回 0,如果不是所有字符都是唯一的,则返回 1