Alguma idéia de como verificar se essa lista é um subconjunto de outra?
Especificamente, eu tenho
List<double> t1 = new List<double> { 1, 3, 5 };
List<double> t2 = new List<double> { 1, 5 };
Como verificar se t2 é um subconjunto de t1, usando LINQ?
Respostas:
fonte
Use HashSet em vez de List se estiver trabalhando com conjuntos. Então você pode simplesmente usar IsSubsetOf ()
Desculpe por não usar o LINQ. :-(
Se você precisar usar listas, a solução do @ Jared funcionará com a ressalva de que você precisará remover todos os elementos repetidos existentes.
fonte
Se você estiver testando a unidade, também poderá utilizar o método CollectionAssert.IsSubsetOf :
No caso acima, isso significaria:
fonte
Esta é uma solução significativamente mais eficiente que as outras postadas aqui, especialmente a solução principal:
Se você puder encontrar um único elemento em t2 que não esteja em t1, saberá que t2 não é um subconjunto de t1. A vantagem desse método é que ele é feito no local, sem alocar espaço adicional, ao contrário das soluções usando .Except ou .Intersect. Além disso, esta solução pode quebrar assim que encontrar um único elemento que viole a condição do subconjunto, enquanto os outros continuam pesquisando. Abaixo está a forma longa ideal da solução, que é marginalmente mais rápida em meus testes do que a solução abreviada acima.
Fiz algumas análises rudimentares de desempenho de todas as soluções e os resultados são drásticos. Essas duas soluções são cerca de 100x mais rápidas que as soluções .Except () e .Intersect () e não usam memória adicional.
fonte
!t2.Except(t1).Any()
está fazendo. O Linq está trabalhando de um lado para o outro.Any()
está perguntandoIEnumerable
se existe pelo menos um elemento. Nesse cenário,t2.Except(t1)
está emitindo apenas o primeiro elemento dot2
qual não estát1
. Se o primeiro elemento det2
não estivert1
nele, ele termina mais rápido, se todos os elementos de lát2
estiverem, sãot1
executados por mais tempo.t1={1,2,3,...9999}
et2={9999,9998,99997...9000}
, você tem as seguintes medidas:!t2.Except(t1).Any(): 1ms -> t2.All(e => t1.Contains(e)): 702ms
. E fica pior quanto maior o alcance.t2.Except (t1)
está retornando umIEnumerable
não aCollection
. Ele só emite todos os itens possíveis se você iterar completamente sobre ele, por exemplo, porToArray ()
ouToList ()
ou usarforeach
sem quebrar o interior. Pesquise a execução adiada do linq para ler mais sobre esse conceito.t2={1,2,3,4,5,6,7,8}
t1={2,4,6,8}
t2.Except(t1)
=> primeiro elemento de t2 = 1 => a diferença de 1 para t1 é 1 (marcada com {2,4,6,8}) =>Except()
emite o primeiro elemento 1 =>Any()
obtém um elemento =>Any()
resulta em true => nenhuma verificação adicional dos elementos em t2.@ A solução da Cameron como método de extensão:
Uso:
(Isso é semelhante, mas não o mesmo que o postado no blog do @ Michael)
fonte
Com base nas respostas de @Cameron e @Neil, escrevi um método de extensão que usa a mesma terminologia que a classe Enumerable.
fonte
por exemplo:
fonte
Tente isto
A idéia aqui é que o Intersect retornará apenas os valores que estão nas duas matrizes. Nesse momento, se o comprimento do conjunto resultante for igual ao conjunto original, todos os elementos em "conjunto" também estarão em "verificação" e, portanto, "conjunto" será um subconjunto de "toCheck"
Nota: Minha solução não funcionará se "set" tiver duplicatas. Não estou mudando, porque não quero roubar os votos de outras pessoas.
Dica: votei na resposta de Cameron.
fonte