Verificar se uma matriz é um subconjunto de uma outra
Pergunta
Qualquer ideia sobre como verificar se essa lista é um subconjunto do outro?
Especificamente, eu tenho
List<double> t1 = new List<double> { 1, 3, 5 };
List<double> t2 = new List<double> { 1, 5 };
Como verificar que t2 é um subconjunto de t1, usando o LINQ?
Solução
bool isSubset = !t2.Except(t1).Any();
Outras dicas
Use HashSet em vez de Lista se trabalhar com conjuntos. Em seguida, você pode simplesmente usar IsSubsetOf ()
HashSet<double> t1 = new HashSet<double>{1,3,5};
HashSet<double> t2 = new HashSet<double>{1,5};
bool isSubset = t2.IsSubsetOf(t1);
Lamentamos que ele não usa LINQ. : - (
Se você precisa de listas de uso, então @ solução funciona de Jared com a ressalva de que você precisará remover todos os elementos repetidos que existem.
Se você é -teste de unidade você também pode utilizar o método CollectionAssert.IsSubsetOf :
CollectionAssert.IsSubsetOf(subset, superset);
No caso acima, isto significaria:
CollectionAssert.IsSubsetOf(t2, t1);
@ solução de Cameron como um método de extensão:
public static bool IsSubsetOf<T>(this IEnumerable<T> a, IEnumerable<T> b)
{
return !a.Except(b).Any();
}
Uso:
bool isSubset = t2.IsSubsetOf(t1);
(Isto é semelhante, mas não exatamente o mesmo que aquele publicado em @ blog de Michael)
Esta é uma solução muito mais eficiente do que os outros postaram aqui, especialmente a solução de topo:
bool isSubset = t2.All(elem => t1.Contains(elem));
Se você puder encontrar um único elemento em t2 que não está em t1, então você sabe que t2 não é um subconjunto de t1. A vantagem deste método é que ele é feito tudo no local, sem alocar espaço adicional, ao contrário das soluções usando .Except ou .Intersect. Além disso, esta solução é capaz de quebrar tão logo ele encontra um único elemento que viola a condição de subconjunto, enquanto os outros continuar a busca. Abaixo está a forma longa ideal da solução, que é apenas marginalmente mais rápido em meus testes do que a solução abreviada acima.
bool isSubset = true;
foreach (var element in t2) {
if (!t1.Contains(element)) {
isSubset = false;
break;
}
}
Eu fiz alguma análise de desempenho rudimentar de todas as soluções, e os resultados são drásticas. Estas duas soluções são cerca de 100 vezes mais rápido do que as soluções .Except () e .Intersect (), e usar nenhuma memória adicional.
Com base nas respostas de @Cameron e @Neil eu escrevi um método de extensão que usa a mesma terminologia como a classe Enumerable.
/// <summary>
/// Determines whether a sequence contains the specified elements by using the default equality comparer.
/// </summary>
/// <typeparam name="TSource">The type of the elements of source.</typeparam>
/// <param name="source">A sequence in which to locate the values.</param>
/// <param name="values">The values to locate in the sequence.</param>
/// <returns>true if the source sequence contains elements that have the specified values; otherwise, false.</returns>
public static bool ContainsAll<TSource>(this IEnumerable<TSource> source, IEnumerable<TSource> values)
{
return !values.Except(source).Any();
}
Aqui nós verificamos que se houver qualquer elemento presente na lista de filhos (ou seja
t2
) que não está contido pela lista pai (ou sejat1
) .Se nenhum tal existe, então a lista é subconjunto do outro
por exemplo:
bool isSubset = !(t2.Any(x => !t1.Contains(x)));
Tente este
static bool IsSubSet<A>(A[] set, A[] toCheck) {
return set.Length == (toCheck.Intersect(set)).Count();
}
A idéia aqui é que Intersect só irá devolver os valores que estão em ambas as matrizes. Neste ponto, se o comprimento do conjunto resultante é o mesmo que o conjunto original, em seguida, todos os elementos em "conjunto" estão também em "verificação" e, portanto, "conjunto" representa um subconjunto de "tocheck"
Nota: Minha solução não funciona se "set" tem duplicatas. Eu não estou mudando isso porque eu não quero roubar votos de outras pessoas.
Dica: Eu votei para a resposta de Cameron.