Controlla se l'elenco <t> contiene uno qualsiasi di un altro elenco


97

Ho un elenco di parametri come questo:

public class parameter
{
    public string name {get; set;}
    public string paramtype {get; set;}
    public string source {get; set;}
}

IEnumerable<Parameter> parameters;

E un array di stringhe con cui voglio verificarlo.

string[] myStrings = new string[] { "one", "two"};

Voglio iterare sull'elenco dei parametri e verificare se la proprietà source è uguale a uno qualsiasi degli array myStrings. Posso farlo con i foreach annidati, ma mi piacerebbe imparare come farlo in un modo più carino dato che ho giocato con linq e mi piacciono i metodi di estensione su enumerabili come dove ecc. Quindi i foreach annidati sembrano sbagliati. Esiste un modo linq / lambda / delegete preferito più elegante per farlo.

Grazie

Risposte:


207

È possibile utilizzare un annidato Any()per questo controllo che è disponibile su qualsiasi Enumerable:

bool hasMatch = myStrings.Any(x => parameters.Any(y => y.source == x));

Più veloce l'esecuzione su collezioni più grandi sarebbe quello di progetto parametersdi sourcee quindi utilizzare Intersect, che usa internamente un HashSet<T>così invece di O (n ^ 2) per il primo approccio (l'equivalente di due cicli annidati) si può fare il check-in O (n):

bool hasMatch = parameters.Select(x => x.source)
                          .Intersect(myStrings)
                          .Any(); 

Inoltre, come commento a margine, dovresti scrivere in maiuscolo i nomi delle classi e delle proprietà per conformarti alle linee guida dello stile C #.


grazie sembra essere quello che sto cercando lo proverò. Hai bisogno di giocare un po 'di più con il lato funzionale delle cose. per quanto riguarda la capitalizzazione di classe e proprietà, mi sono semplicemente dimenticato quando ho scritto l'esempio sopra.
PIL

1
Perché O (n ^ 2)? Non è O (n * m) visto che stiamo parlando di due variabili e non di una? Poiché m (i parametri) sono una costante, è uguale a O (n). Non vedo come l'intersezione dovrebbe essere molto più veloce qui? Ma d'accordo, Intersect ha il potenziale per essere più veloce, ma non è garantito.
Squazz

Hai ragione che dovrebbe essere O (n * m) - m non è una costante però - è la dimensione di una delle liste, anche se nell'esempio dato potrebbe essere "2". Anche i valori costanti però non sono trascurabili in pratica - per tutte le lunghezze di lista non banali Intersectsarà più veloce - se le liste sono banalmente brevi, non ha importanza in un modo o nell'altro (in quel caso le prestazioni probabilmente non ti interessano affatto comunque )
BrokenGlass

come puoi capire l'indice della lista in cui la condizione diventa vera? Ho una lista di frasi. Ho una matrice con parole particolari. Voglio gli indici della lista se la frase ha almeno una parola dall'array. @BrokenGlass
kirushan

1
Dal punto di vista delle prestazioni, non parameters.Any(x => myStrings.Contains(x.source));sarebbe migliore del tuo primo esempio?
Fluppe

3

Ecco un esempio per scoprire se sono presenti elementi di corrispondenza in un altro elenco

List<int> nums1 = new List<int> { 2, 4, 6, 8, 10 };
List<int> nums2 = new List<int> { 1, 3, 6, 9, 12};

if (nums1.Any(x => nums2.Any(y => y == x)))
{
    Console.WriteLine("There are equal elements");
}
else
{
    Console.WriteLine("No Match Found!");
}

2
Nota che se gli elenchi coinvolti sono grandi, questo finirà per essere molto più lento Intersectdell'approccio, poiché è O (N * M) nelle dimensioni degli elenchi. (È O (1) in memoria però.)
Jon Skeet

1

Se entrambi gli elenchi sono troppo grandi e quando usiamo l'espressione lamda, il recupero richiederà molto tempo. Meglio usare linq in questo caso per recuperare l'elenco dei parametri:

var items = (from x in parameters
                join y in myStrings on x.Source equals y
                select x)
            .ToList();
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.