2010-03-04 16 views
40

Se si dispone di un oggetto IEnumerable in cui ClassA espone una proprietà ID di tipo long. È possibile utilizzare una query Linq per ottenere tutte le istanze di ClassA con ID appartenenti a un secondo IEnumerable?Interrogazione query LINQ

In altre parole, può essere fatto?

IEnumerable<ClassA> = original.Intersect(idsToFind....)? 

dove originale è una IEnumerable<ClassA> e idsToFind è IEnumerable<long>.

risposta

50

Sì.

Come altre persone hanno risposto, è possibile utilizzare Where, ma sarà estremamente inefficiente per i set di grandi dimensioni.

Se le prestazioni sono un problema, è possibile chiamare Join:

var results = original.Join(idsToFind, o => o.Id, id => id, (o, id) => o); 

Se idsToFind può contenere duplicati, è necessario sia chiamare Distinct() sugli ID o sui risultati o sostituire Join con GroupJoin (The i parametri per GroupJoin sarebbero uguali).

+0

Questo è quello che stavo cercando, grazie. In qualche modo, questo non è riuscito nella mia versione originale ma idsToFind = IEnumerable . Grazie ancora. –

+1

Qualche idea a quale dimensione di 'original' o' idsToFind' il 'Join' inizia ad essere più efficiente della soluzione' Where'/'Contains'? Posso immaginare che per le piccole liste (forse 20-30 voci) il 'Join' abbia troppe spese generali? – Tobias

1

utilizzare il metodo Where per filtrare i risultati:

var result = original.Where(o => idsToFind.Contains(o.ID)); 
5

Un modo semplice potrebbe essere:

IEnumerable<ClassA> result = original.Where(a => idsToFind.contains(a.ID)); 
9

si può fare, ma nella forma attuale, che ci si vuole utilizzare il metodo di estensione Where.

var results = original.Where(x => yourEnumerable.Contains(x.ID)); 

Intersect d'altra parte troverà elementi che sono in entrambi i 's IEnumerable. Se siete alla ricerca di un semplice elenco di ID, è possibile effettuare le seguenti operazioni che sfrutta Intersect

var ids = original.Select(x => x.ID).Intersect(yourEnumerable); 
13

Invierò una risposta utilizzando Intersect.

Questo è utile se si desidera intersecare 2 IEnumerables dello stesso tipo.

prima si devono un EqualityComparer:

public class KeyEqualityComparer<T> : IEqualityComparer<T> 
    { 
     private readonly Func<T, object> keyExtractor; 

     public KeyEqualityComparer(Func<T, object> keyExtractor) 
     { 
      this.keyExtractor = keyExtractor; 
     } 

     public bool Equals(T x, T y) 
     { 
      return this.keyExtractor(x).Equals(this.keyExtractor(y)); 
     } 

     public int GetHashCode(T obj) 
     { 
      return this.keyExtractor(obj).GetHashCode(); 
     } 
    } 

In secondo luogo applichiamo le KeyEqualityComparer alla funzione Intersect:

var list3= list1.Intersect(list2, new KeyEqualityComparer<ClassToCompare>(s => s.Id));