Ho un piccolo elenco di byte e voglio verificare che siano tutti valori diversi. Ad esempio, ho questo:
List<byte> theList = new List<byte> { 1,4,3,6,1 };
Qual è il modo migliore per verificare se tutti i valori sono distinti o meno?
Ho un piccolo elenco di byte e voglio verificare che siano tutti valori diversi. Ad esempio, ho questo:
List<byte> theList = new List<byte> { 1,4,3,6,1 };
Qual è il modo migliore per verificare se tutti i valori sono distinti o meno?
Risposte:
bool isUnique = theList.Distinct().Count() == theList.Count();
Ecco un altro approccio più efficiente di Enumerable.Distinct+ Enumerable.Count(tanto più se la sequenza non è un tipo di raccolta). Usa un HashSet<T>che elimina i duplicati, è molto efficiente nelle ricerche e ha una proprietà count:
var distinctBytes = new HashSet<byte>(theList);
bool allDifferent = distinctBytes.Count == theList.Count;
o un altro approccio, più sottile ed efficiente:
var diffChecker = new HashSet<byte>();
bool allDifferent = theList.All(diffChecker.Add);
HashSet<T>.Addrestituisce falsese l'elemento non può essere aggiunto poiché era già nel file HashSet. Enumerable.Allsi ferma sul primo "falso".
Assert.IsTrue(samples.Add(AwesomeClass.GetUnique()));. Erano e sono :) +1 per te Tim :)
bool allDifferent = theList.All(s => diffChecker.Add(s))
List.All(HashSet.Add)) sembra essere molto più veloce degli altri due in quasi tutti i casi
Ok, ecco il metodo più efficiente che riesco a pensare di usare .Net standard
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;
}
}
essenzialmente, qual è il punto di enumerare l'intera sequenza due volte se tutto ciò che vuoi fare è trovare il primo duplicato.
Potrei ottimizzarlo di più inserendo in maiuscolo una sequenza di elementi vuoti e singoli, ma ciò si deprezzerebbe dalla leggibilità / manutenibilità con un guadagno minimo.
sequencedovrebbe essere source). Ma funziona benissimo una volta che questi sono stati risolti
if (!checkBuffer.Add(t)) { firstDuplicate = t; return true }nel ciclo.
La logica simile Distinctall'utilizzo di GroupBy:
var isUnique = theList.GroupBy(i => i).Count() == theList.Count;
theList.GroupBy(o => o.SomeProperty).Count() == theList.Count;mentre Distinct () non lo consente.
Ci sono molte soluzioni.
E senza dubbio quelli più belli con l'uso di LINQ come "juergen d" e "Tim Schmelter" menzionati.
Ma, se metti a nudo "Complessità" e velocità, la soluzione migliore sarà implementarla da solo. Una delle soluzioni sarà creare un array di dimensione N (per byte è 256). E il ciclo dell'array, e ad ogni iterazione testerà l'indice del numero corrispondente se il valore è 1 se lo fa, ciò significa che ho già incrementato l'indice dell'array e quindi l'array non è distinto altrimenti incrementerò la cella dell'array e continuerò a controllare .
E un'altra soluzione, se vuoi trovare valori duplicati.
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));
}
Produzione:
duplicated value: 2
duplicated value: 7
Controllo se un IEnumerable (aray, list, ecc.) È unico in questo modo:
var isUnique = someObjectsEnum.GroupBy(o => o.SomeProperty).Max(g => g.Count()) == 1;