Mam małą listę bajtów i chcę sprawdzić, czy są to różne wartości. Na przykład mam to:
List<byte> theList = new List<byte> { 1,4,3,6,1 };
Jaki jest najlepszy sposób sprawdzenia, czy wszystkie wartości są różne, czy nie?
Mam małą listę bajtów i chcę sprawdzić, czy są to różne wartości. Na przykład mam to:
List<byte> theList = new List<byte> { 1,4,3,6,1 };
Jaki jest najlepszy sposób sprawdzenia, czy wszystkie wartości są różne, czy nie?
Odpowiedzi:
bool isUnique = theList.Distinct().Count() == theList.Count();
Oto inne podejście, które jest bardziej wydajne niż Enumerable.Distinct+ Enumerable.Count(tym bardziej, jeśli sekwencja nie jest typem kolekcji). Używa a, HashSet<T>który eliminuje duplikaty, jest bardzo wydajny w wyszukiwaniu i ma właściwość count:
var distinctBytes = new HashSet<byte>(theList);
bool allDifferent = distinctBytes.Count == theList.Count;
lub inne - bardziej subtelne i wydajne - podejście:
var diffChecker = new HashSet<byte>();
bool allDifferent = theList.All(diffChecker.Add);
HashSet<T>.Addzwraca, falsejeśli element nie mógł zostać dodany, ponieważ znajdował się już w HashSet. Enumerable.Allzatrzymuje się na pierwszym „fałszu”.
Assert.IsTrue(samples.Add(AwesomeClass.GetUnique()));. Byli i są :) +1 dla Ciebie Tim :)
bool allDifferent = theList.All(s => diffChecker.Add(s))
List.All(HashSet.Add)) wydaje się być znacznie szybszy niż pozostałe dwa w prawie wszystkich przypadkach
Okay, oto najbardziej wydajna metoda, jaką mogę wymyślić, używając standardowego .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;
}
}
Zasadniczo jaki jest sens wyliczenia całej sekwencji dwukrotnie, jeśli wszystko, co chcesz zrobić, to znaleźć pierwszy duplikat.
Mógłbym to bardziej zoptymalizować przez specjalne obudowanie pustych i pojedynczych sekwencji elementów, ale to osłabiłoby czytelność / łatwość konserwacji przy minimalnym zysku.
sequencePowinno być source). Ale działa świetnie, gdy zostaną naprawione
if (!checkBuffer.Add(t)) { firstDuplicate = t; return true }w pętli.
Podobna logika do Distinctużywania GroupBy:
var isUnique = theList.GroupBy(i => i).Count() == theList.Count;
theList.GroupBy(o => o.SomeProperty).Count() == theList.Count;podczas gdy Distinct () na to nie pozwala.
Rozwiązań jest wiele.
I bez wątpienia piękniejsze z użyciem LINQ, jak wspomnieli „juergen d” i „Tim Schmelter”.
Ale jeśli poznajesz „złożoność” i szybkość, najlepszym rozwiązaniem będzie samodzielne wdrożenie. Jednym z rozwiązań będzie utworzenie tablicy o rozmiarze N (dla bajtów to 256). I zapętl tablicę, a przy każdej iteracji przetestuje pasujący indeks liczbowy, jeśli wartość wynosi 1, jeśli tak, oznacza to, że już zwiększam indeks tablicy, a zatem tablica nie jest odrębna, w przeciwnym razie zwiększę komórkę tablicy i kontynuuję sprawdzanie .
I inne rozwiązanie, jeśli chcesz znaleźć zduplikowane wartości.
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));
}
Wynik:
duplicated value: 2
duplicated value: 7
Sprawdzam, czy IEnumerable (aray, list itp.) Jest unikalny w następujący sposób:
var isUnique = someObjectsEnum.GroupBy(o => o.SomeProperty).Max(g => g.Count()) == 1;