У мене є невеликий список байтів, і я хочу перевірити, чи всі вони різні значення. Наприклад, у мене є таке:
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(тим більше, якщо послідовність не є типом колекції). Він використовує a, 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 (масив, список тощо) унікальний, як це:
var isUnique = someObjectsEnum.GroupBy(o => o.SomeProperty).Max(g => g.Count()) == 1;