У меня есть небольшой список байтов, и я хочу проверить, что все они имеют разные значения. Например, у меня есть это:
List<byte> theList = new List<byte> { 1,4,3,6,1 };
Как лучше всего проверить, все ли значения различны или нет?
У меня есть небольшой список байтов, и я хочу проверить, что все они имеют разные значения. Например, у меня есть это:
List<byte> theList = new List<byte> { 1,4,3,6,1 };
Как лучше всего проверить, все ли значения различны или нет?
Ответы:
bool isUnique = theList.Distinct().Count() == theList.Count();
Вот еще один подход, который более эффективен, чем Enumerable.Distinct+ Enumerable.Count(тем более, если последовательность не является типом коллекции). Он использует, HashSet<T>который удаляет дубликаты, очень эффективен при поиске и имеет свойство count:
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останавливается на первом «ложном».
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 }в курсе.
Аналогичная логика Distinctиспользования GroupBy:
var isUnique = theList.GroupBy(i => i).Count() == theList.Count;
theList.GroupBy(o => o.SomeProperty).Count() == theList.Count;то время как Distinct () не позволяет этого.
Есть много решений.
И, без сомнения, более красивые, с использованием 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 и т.д.) следующим образом:
var isUnique = someObjectsEnum.GroupBy(o => o.SomeProperty).Max(g => g.Count()) == 1;