Domanda

Qualche idea su come verificare se tale elenco è un sottoinsieme di un altro?

In particolare, ho

List<double> t1 = new List<double> { 1, 3, 5 };
List<double> t2 = new List<double> { 1, 5 };

Come verificare che t2 sia un sottoinsieme di t1, usando LINQ?

È stato utile?

Soluzione

bool isSubset = !t2.Except(t1).Any();

Altri suggerimenti

Usa HashSet invece di Elenco se lavori con i set. Quindi puoi semplicemente utilizzare IsSubsetOf ()

HashSet<double> t1 = new HashSet<double>{1,3,5};
HashSet<double> t2 = new HashSet<double>{1,5};

bool isSubset = t2.IsSubsetOf(t1);

Mi dispiace che non usi LINQ. : - (

Se è necessario utilizzare gli elenchi, la soluzione di @ Jared funziona con l'avvertenza che sarà necessario rimuovere tutti gli elementi ripetuti esistenti.

Se stai test unitari puoi anche utilizzare Metodo CollectionAssert.IsSubsetOf :

CollectionAssert.IsSubsetOf(subset, superset);

Nel caso sopra questo significherebbe:

CollectionAssert.IsSubsetOf(t2, t1);

La soluzione di @ Cameron come metodo di estensione:

public static bool IsSubsetOf<T>(this IEnumerable<T> a, IEnumerable<T> b)
{
    return !a.Except(b).Any();
}

Utilizzo:

bool isSubset = t2.IsSubsetOf(t1);

(Questo è simile, ma non è lo stesso di quello pubblicato sul blog di @ Michael)

Questa è una soluzione significativamente più efficiente rispetto alle altre pubblicate qui, in particolare la soluzione migliore:

bool isSubset = t2.All(elem => t1.Contains(elem));

Se riesci a trovare un singolo elemento in t2 che non è in t1, allora sai che t2 non è un sottoinsieme di t1. Il vantaggio di questo metodo è che viene eseguito tutto sul posto, senza allocare spazio aggiuntivo, a differenza delle soluzioni che utilizzano .Except o .Intersect. Inoltre, questa soluzione è in grado di rompersi non appena trova un singolo elemento che viola la condizione del sottoinsieme, mentre gli altri continuano a cercare. Di seguito è la forma lunga ottimale della soluzione, che è solo leggermente più veloce nei miei test rispetto alla precedente soluzione abbreviata.

bool isSubset = true;
foreach (var element in t2) {
    if (!t1.Contains(element)) {
        isSubset = false;
        break;
    }
}

Ho fatto un'analisi rudimentale delle prestazioni di tutte le soluzioni e i risultati sono drastici. Queste due soluzioni sono circa 100 volte più veloci delle soluzioni .Except () e .Intersect () e non utilizzano memoria aggiuntiva.

Basandomi sulle risposte di @Cameron e @Neil ho scritto un metodo di estensione che utilizza la stessa terminologia della 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();
}
  

Qui controlliamo che se ci sono elementi presenti nella lista figlio (es. t2 ) che non è contenuta nella lista padre (es. t1 ). tale esiste quindi l'elenco è un sottoinsieme dell'altro

es:

bool isSubset = !(t2.Any(x => !t1.Contains(x)));

Prova questo

static bool IsSubSet<A>(A[] set, A[] toCheck) {
  return set.Length == (toCheck.Intersect(set)).Count();
}

L'idea qui è che Intersect restituirà solo i valori che si trovano in entrambi gli array. A questo punto se la lunghezza dell'insieme risultante è la stessa dell'insieme originale, allora tutti gli elementi in "set" sono anche in " controlla " e quindi "impostare" è un sottoinsieme di " da verificare "

Nota: la mia soluzione non funziona se " imposta " ha duplicati. Non lo sto cambiando perché non voglio rubare i voti degli altri.

Suggerimento: ho votato per la risposta di Cameron.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top