Eu tenho uma pequena lista de bytes e quero testar se são todos valores diferentes. Por exemplo, eu tenho este:
List<byte> theList = new List<byte> { 1,4,3,6,1 };
Qual é a melhor maneira de verificar se todos os valores são distintos ou não?
Eu tenho uma pequena lista de bytes e quero testar se são todos valores diferentes. Por exemplo, eu tenho este:
List<byte> theList = new List<byte> { 1,4,3,6,1 };
Qual é a melhor maneira de verificar se todos os valores são distintos ou não?
Respostas:
bool isUnique = theList.Distinct().Count() == theList.Count();
Aqui está outra abordagem que é mais eficiente do que Enumerable.Distinct+ Enumerable.Count(ainda mais se a sequência não for um tipo de coleção). Ele usa um HashSet<T>que elimina duplicatas, é muito eficiente em pesquisas e tem uma propriedade de contagem:
var distinctBytes = new HashSet<byte>(theList);
bool allDifferent = distinctBytes.Count == theList.Count;
ou outra abordagem - mais sutil e eficiente:
var diffChecker = new HashSet<byte>();
bool allDifferent = theList.All(diffChecker.Add);
HashSet<T>.Addretorna falsese o elemento não pôde ser adicionado, pois já estava no HashSet. Enumerable.Allpára no primeiro "falso".
Assert.IsTrue(samples.Add(AwesomeClass.GetUnique()));. Eles foram e são :) +1 para você Tim :)
bool allDifferent = theList.All(s => diffChecker.Add(s))
List.All(HashSet.Add)) parece ser muito mais rápido que os outros dois em quase todos os casos
Ok, aqui está o método mais eficiente que posso pensar em usar .Net padrão
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;
}
}
essencialmente, qual é o ponto de enumerar toda a sequência duas vezes se tudo o que você deseja fazer é encontrar a primeira duplicata.
Eu poderia otimizar isso mais pelo caso especial de sequências de elemento vazio e único, mas isso depreciaria a legibilidade / manutenção com ganho mínimo.
sequencedeveriam estar source). Mas funciona muito bem depois de consertados
if (!checkBuffer.Add(t)) { firstDuplicate = t; return true }no loop.
A lógica semelhante ao Distinctuso de GroupBy:
var isUnique = theList.GroupBy(i => i).Count() == theList.Count;
theList.GroupBy(o => o.SomeProperty).Count() == theList.Count;enquanto Distinct () não permite isso.
Existem muitas soluções.
E sem dúvida outros mais bonitos com o uso do LINQ como "juergen d" e "Tim Schmelter" mencionados.
Mas, se você tiver "Complexidade" e velocidade, a melhor solução será implementá-la sozinho. Uma das soluções será criar um array de tamanho N (para byte é 256). E fazer um loop no array, e em cada iteração testará o índice de número correspondente se o valor for 1 se for o caso, isso significa que eu já incremento o índice do array e, portanto, o array não é distinto, caso contrário irei incrementar a célula do array e continuar verificando .
E outra solução, se você quiser encontrar valores duplicados.
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));
}
Resultado:
duplicated value: 2
duplicated value: 7
Eu verifico se um IEnumerable (aray, list, etc) é único como este:
var isUnique = someObjectsEnum.GroupBy(o => o.SomeProperty).Max(g => g.Count()) == 1;