C# 测试列表中的所有值是否唯一
我有一个小的字节列表,我想测试它们是否都是不同的值。 例如,我有:C# 测试列表中的所有值是否唯一,c#,C#,我有一个小的字节列表,我想测试它们是否都是不同的值。 例如,我有: List<byte> theList = new List<byte> { 1,4,3,6,1 }; List theList=新列表{1,4,3,6,1}; 检查所有值是否不同的最佳方法是什么?有很多解决方案 bool isUnique = theList.Distinct().Count() == theList.Count(); 毫无疑问,更漂亮的是使用了LINQ,如“juergen d”和“
List<byte> theList = new List<byte> { 1,4,3,6,1 };
List theList=新列表{1,4,3,6,1};
检查所有值是否不同的最佳方法是什么?有很多解决方案
bool isUnique = theList.Distinct().Count() == theList.Count();
毫无疑问,更漂亮的是使用了LINQ,如“juergen d”和“Tim Schmelter”所述
但是,如果你没有“复杂性”和速度,最好的解决方案是自己实现它。
解决方案之一是,创建一个大小为N的数组(字节为256)。
循环数组,在每次迭代中,如果值为1,则测试匹配数索引,如果值为1,这意味着我已经增加了数组索引,因此数组不是独立的,否则我将增加数组单元格并继续检查。这里有另一种方法,它比
Enumerable.distinct
+Enumerable.Count
(如果序列不是集合类型,则更有效)。它使用一个哈希集
,该哈希集消除了重复项,在查找中非常有效,并且具有count属性:
var distinctBytes = new HashSet<byte>(theList);
bool allDifferent = distinctBytes.Count == theList.Count;
var distinctBytes=新哈希集(列表);
bool allDifferent=distinctBytes.Count==list.Count;
或者另一种更微妙、更有效的方法:
var diffChecker = new HashSet<byte>();
bool allDifferent = theList.All(diffChecker.Add);
var diffChecker=newhashset();
bool allDifferent=list.All(diffChecker.Add);
如果元素已在
哈希集中,因此无法添加,则返回false
<代码>可枚举。所有
在第一个“false”处停止。和另一个解决方案,如果要查找重复的值
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));
}
好的,下面是我能想到的使用标准.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;
}
}
使用系统;
使用System.Collections.Generic;
公共静态类扩展
{
公共静态布尔值(
这是一个数不清的来源,
输出(第一次重复)
{
if(source==null)
{
抛出新ArgumentNullException(nameof(source));
}
var checkBuffer=newhashset();
foreach(源中的var t)
{
if(checkBuffer.Add(t))
{
继续;
}
第一重复=t;
返回true;
}
firstDuplicate=默认值(T);
返回false;
}
}
从本质上讲,如果您只想找到第一个重复项,那么枚举整个序列两次有什么意义
我可以通过为空的单元素序列加上特殊的外壳来进一步优化这一点,但这会使可读性/可维护性降低,且收益最小。使用
GroupBy
,类似于Distinct
:
var isUnique = theList.GroupBy(i => i).Count() == theList.Count;
也可以这样做:使用Hashset
var uniqueIds = new HashSet<long>(originalList.Select(item => item.Id));
if (uniqueIds.Count != originalList.Count)
{
}
var uniqueIds=newhashset(originalList.Select(item=>item.Id));
if(uniqueid.Count!=originalList.Count)
{
}
我检查IEnumerable(aray、list等)是否是唯一的,如下所示:
var isUnique = someObjectsEnum.GroupBy(o => o.SomeProperty).Max(g => g.Count()) == 1;
由于这是一个典型的教室问题,我将用一个问题来回答。如果它被分类,你会怎么做?只是好奇:这有什么空间和时间要求?@dtb。当然,考虑到这是一个“小列表”,几乎任何算法都会有闪电般的速度。在我看来,这在可读性和简洁性上是成功的,因为速度不是问题,这使它变得完美。这比使用256位=32字节=8整数的位向量更有效。但是你的大O=O(n)仍然与使用另一个答案中提出的哈希集相同。这是O(n),所以可能是最快的,(测试它)。在你走的时候检查计数还是在最后检查计数是最快的?我怀疑最终会改善最坏的情况,但随着时间的推移,可能会改善平均情况和最佳情况)。如果没有重复,这将是最糟糕的性能。同样,对于更大的数据类型,这也不能很好地工作,对于16位类型,您必须使用64k的计数,以及64k位(8k字节),但是对于任何更大的数据类型,内存使用将开始变得愚蠢。但是我喜欢这个8位值的答案。@TamusJRoyce如果你想存储4294967296种可能性,你需要4GB而不是42MB(或者512MB你使用位屏蔽),我不确定我在想什么。“分配42MB+的内存来容纳所有4294967296的可能性。并使用简单的桶计数器。甚至使用位屏蔽异或,检查是否有任何位从真变假。42MB+/8=5MB+对于今天的硬件来说,花费似乎太大了。但有一天这可能会有价值。”这不是一个真正相关的评论。哈希集最好。如果您处理的是非常大的数组,则需要非常大的内存。但在这种奇怪的边缘情况下,使用CRC算法的heristic会更好。将其映射到多项式。如果关闭,请进行评估。谢谢你@tigrou!这么简单和明显,为什么我不先考虑一下呢:)我在单元测试中使用了这个一行代码来确认我的优秀代码生成的1000万个元素是真正唯一的
Assert.IsTrue(samples.Add(AwesomeClass.GetUnique())代码>。他们过去是,现在是:)+1给你蒂姆:)我试过你的答案,但不起作用先生:应该是这样:bool allDifferent=theList.All=>diffChecker.Add(s))
No,不需要。在这种情况下,您可以传递委托directly@Andréreichlet-我刚刚打开了你的代码,第三个场景(List.All(HashSet.Add)
)似乎比其他两个场景在几乎所有情况下都要快得多,只需添加一个重复的值输出返回,对于验证非常有用我在这里测试了3个解决方案,这确实是本页中最有效的。尽管有一些打字错误(例如序列
应该是源代码
)。但一旦这些都是fixed@mikenelson,这应该是更好的可读性,我认为它应该是如果(!checkBuffer.Add(t)){firstDuplicate=t;return true}
在循环中。如果您想检查属性的唯一性,这很有用
var isUnique = someObjectsEnum.GroupBy(o => o.SomeProperty).Max(g => g.Count()) == 1;