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?

Foi útil?

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 seja t1) .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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top