【发布时间】:2013-08-20 15:58:03
【问题描述】:
我有一个小字节列表,我想测试它们是否都是不同的值。 例如,我有这个:
List<byte> theList = new List<byte> { 1,4,3,6,1 };
检查所有值是否不同的最佳方法是什么?
【问题讨论】:
-
因为这是一个典型的课堂问题,所以我会回答一个问题。如果是排序的,你会怎么做?
标签: c#
我有一个小字节列表,我想测试它们是否都是不同的值。 例如,我有这个:
List<byte> theList = new List<byte> { 1,4,3,6,1 };
检查所有值是否不同的最佳方法是什么?
【问题讨论】:
标签: c#
bool isUnique = theList.Distinct().Count() == theList.Count();
【讨论】:
这是另一种比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”处停止。
【讨论】:
Assert.IsTrue(samples.Add(AwesomeClass.GetUnique()));。他们过去和现在都是 :) 为你 +1 蒂姆 :)
bool allDifferent = theList.All(s => diffChecker.Add(s))
List.All(HashSet.Add)) 似乎在几乎所有情况下都比其他两种情况快得多
好的,这是我能想到的使用标准 .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;
}
}
本质上,如果您只想找到第一个重复项,那么枚举整个序列两次有什么意义。
我可以通过特殊封装一个空的单元素序列来进一步优化这一点,但这会以最小的增益降低可读性/可维护性。
【讨论】:
sequence 应该是source)。但是一旦这些问题得到解决,效果就会很好
if (!checkBuffer.Add(t)) { firstDuplicate = t; return true }。
使用GroupBy与Distinct类似的逻辑:
var isUnique = theList.GroupBy(i => i).Count() == theList.Count;
【讨论】:
theList.GroupBy(o => o.SomeProperty).Count() == theList.Count; 的唯一性,而 Distinct() 不允许这样做,这很有用。
也可以这样做:使用哈希集
var uniqueIds = new HashSet<long>(originalList.Select(item => item.Id));
if (uniqueIds.Count != originalList.Count)
{
}
【讨论】:
有很多解决方案。
毫无疑问,使用 LINQ 的“juergen d”和“Tim Schmelter”更漂亮。
但是,如果您只考虑“复杂性”和速度,最好的解决方案就是自己实施。 解决方案之一是创建一个 N 大小的数组(字节为 256)。 并循环数组,并且在每次迭代中,如果值为 1,则测试匹配的数字索引,这意味着我已经增加了数组索引,因此数组不是不同的,否则我将增加数组单元格并继续检查.
【讨论】:
如果您想查找重复值,还有另一种解决方案。
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
【讨论】:
我检查一个 IEnumerable (aray, list, etc) 是否像这样是唯一的:
var isUnique = someObjectsEnum.GroupBy(o => o.SomeProperty).Max(g => g.Count()) == 1;
【讨论】: