2013-06-25 17 views
5

Mam serię list:zapytania wiele list w jednym iść

List<foo> spamSpamAndSpam; 
List<foo> spamSpamSpamSausageEggsAndSpam; 
List<foo> spamSpamSpamSausageEggsBaconAndSpam; 
List<foo> spamSpamSpamSpamSpamWithoutSpam; 
List<foo> spamSpamSpamSpamSpamSpamSpamSpamSpamLovelySpamWonderfulSpam; 

Mam też szereg wartości szukam w mieniu foo:

List<string> Brian= new List<string>(); 
Brian.Add("Always"); 
Brian.Add("Look"); 
Brian.Add("On"); 
Brian.Add("The"); 
Brian.Add("Bright"); 
Brian.Add("Side"); 
Brian.Add("Of"); 
Brian.Add("Life"); 

I m przechwytuje odniesienia do wszystkich foo "sesji, w których dana właściwość (na przykład bar) ma wartość zawartą na drugiej liście. Robię to tak:

func<foo, bool> deadParrot = x => Brian.Contains(x.bar); 

IEnumerable<foo> okLumberjacks = spamSpamAndSpam.Where(deadParrot); 
okLumberjacks = okLumberjacks.Concat(
    spamSpamSpamSpamSausageEggsAndSpam.Where(deadParrot)); 

// And so on, concatenating the results of Where() from every list of <foo>. 

muszę za każdym foo który dopasowany funkcję filtrowania w jednym IEnumerable<foo> tak, że można wywołać metodę we wszystkich z nich za jednym razem, tak:

foreach (foo incontinentRunner in okLumberjacks) 
{ 
    incontinentRunner.SillyWalk(); 
} 

Więc moje pytanie brzmi ... Czy istnieje sposób, aby zebrać wszelkie foo w jednej kolekcji, bez konieczności uciekania się do czegoś takiego:

ni = ni.Concat(someList.Where(filter)); 

I Czy istnieje jakiś bardziej elegancki sposób na zrobienie czegoś takiego z Linq? Szukam coś takiego:

okLumberjacks = spamSpamAndSpam. 
    And(spamSpamSpamSausageEggsAndSpam). 
    And(spamSpamSpamSausageEggsBaconAndSpam) /* etc */ .Where(deadParrot); 

Albo jeszcze lepiej:

okLumberjacks = spanishInquisition.Where(deadParrot); 
// Where the type of spanishInquisition is List<List<foo>>. 

nie chcę zmodyfikować oryginalne listy foo bo muszę je, ponieważ są one dla innej operacji na później w kodzie.

+0

Wszystkie wywołania 'OfType' w twoim kodzie nic nie robią; masz już 'IEnumerable' określonego typu, więc jest to po prostu noop. – Servy

+0

@Servy dobry punkt. Ale używam Sharepointa ... Żadna z jego klas kolekcji nie implementuje 'IEnumerable ', ani nie eksponuje metody rozszerzenia 'Where', ale wszystkie eksponują' OfType', a ja jestem nowy w Linq. Edytuję pytanie, aby usunąć 'OfType'. – Renan

+4

+1, aby uzyskać więcej odnośników do Monty Pythona, niż sądziłem, że jest to możliwe w pytaniu dotyczącym SO. – Kevin

Odpowiedz

5

Tworzenie listy list, a potem po prostu spłaszczyć go:

List<List<foo>> lists = new List<List<foo>>() 
{ 
    spamSpamAndSpam, 
    spamSpamSpamSausageEggsAndSpam, 
    //etc. 
}; 

IEnumerable<foo> items = lists.SelectMany(item => item); 
//do stuff with items. 
+0

Nice.Tego właśnie szukałem :) – Renan

2

Najlepszy mogę myśleć byłoby coś takiego:

var everything = spam1.Concat(spam2).Concat(spam3); 
var itemsIWant = everything.Where(x => Brian.Contains(x)); 
+0

Zamiast zagnieżdżać operacje 'Concat', możesz łączyć je dla łatwiejszej składni:' first.Concat (second) .Concat (third) .Concat (fourth); ' – Servy

+0

@Servy: Thanks ... wiedział, że coś wygląda dziwnie. –

+0

Nie wiem, dlaczego nie próbowałem tego ... Myślałem, że to zmieni oryginalne listy, ale po prostu przetestowałem i widzę, że tak nie jest. +1. – Renan

1

Does Unii() rozwiązało problem?

 List<foo> spamSpamAndSpam; 
     List<foo> spamSpamSpamSausageEggsAndSpam; 
     List<foo> spamSpamSpamSausageEggsBaconAndSpam; 
     List<foo> spamSpamSpamSpamSpamWithoutSpam; 
     List<foo> spamSpamSpamSpamSpamSpamSpamSpamSpamLovelySpamWonderfulSpam; 

     var x = spamSpamAndSpam 
      .Union(spamSpamSpamSausageEggsAndSpam) 
      .Union(spamSpamSpamSausageEggsBaconAndSpam) 
      .Union(spamSpamSpamSausageEggsBaconAndSpam) 
      .Union(spamSpamSpamSpamSpamWithoutSpam) 
      .Union(spamSpamSpamSpamSpamSpamSpamSpamSpamLovelySpamWonderfulSpam) 
      .Where(x => .....); 

UWAGA: jak to było właściwie zauważyć, Union wyklucza duplikaty z zestawu powrotnej. Jest to inne zachowanie niż metoda Concat, która zwraca wszystkie elementy w wejściowych sekwencjach, w tym duplikaty. Ponieważ podwójne wykluczenie nie było wymogiem, Concat jest prawdopodobnie lepszy

+0

Czy też. Dzięki, dużo się uczę z tym pytaniem. Ponownie przeczytam dokumentację dla każdej metody rozszerzenia, kiedy wrócę do domu. – Renan

+0

Unia usunęłaby duplikaty, których nie określił jako wyraźnego celu. A jeśli nie ma duplikatów, marnujesz czas/wysiłek/sprawdzanie pamięci. 'Concat' jest praktycznie taki sam jak" Union ", ale bez sprawdzania dup i wydaje się być bardziej odpowiednim operatorem tutaj. – Servy

+0

@Servy, dobrze wiedzieć. Ale powielanie jest testowane przez operatora ds. Równości, prawda? Tak więc dwa obiekty o tych samych wartościach właściwości nadal będą oceniane jako odrębne, prawda? – Renan