2013-06-25 67 views
5

我有一系列的列表:在一個查詢多個列表去

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

我也有一系列的值,我在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"); 

我m會引用所有foo的參數,其中給定的屬性(比如bar)的值包含在後面的列表中。我做這樣的:

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>. 

我需要每foo已經匹配濾波功能單一IEnumerable<foo>這樣我可以調用所有這些方法中一氣呵成,就像這樣:

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

所以我的問題是...是有辦法聚集在一個單一的集合中的每個foo,而無需求助於類似:

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

我意思是說,有沒有更好的方法來用Linq做這樣的事情?我在尋找類似:

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

甚至更​​好:

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

我不想因爲我需要他們,因爲他們是另一個操作以後修改的foo原有名單在代碼中。

+0

代碼中的所有'OfType'調用都不會執行任何操作;你已經有了一個指定類型的IEnumerable,所以它只是一個noop。 – Servy

+0

@Servy好點。但我使用的是Sharepoint ...它的集合類沒有一個實現IEnumerable ,也沒有展示Where的擴展方法,但它們都暴露了OfType,而我是Linq的新手。我正在編輯該問題以刪除「OfType」。 – Renan

+4

+1對於更多的Monty Python引用,我認爲可能在SO問題中。 – Kevin

回答

5

創建一個列表的列表,然後只需壓平:

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

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

不錯。這是我正在尋找:) – Renan

2

我能想到的最好的將是這樣的:

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

而不是嵌套'Concat'操作,你可以鏈接他們更簡單的語法:'first.Concat(second).Concat(third).Concat(fourth);' – Servy

+0

@Servy:Thanks ...知道一些看起來很奇怪。 –

+0

我不知道爲什麼我不這麼做......我認爲這會改變原來的列表,但我只是測試過,我發現它沒有。 +1。 – Renan

1

確實聯盟()解決問題了嗎?

 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 => .....); 

注:,因爲它被正確地指出,Union排除從返回集中的重複。這與Concat方法的行爲不同,後者返回輸入序列中的所有元素,包括重複項。由於不需要重複排除,因此Concat可能更好

+0

也是。謝謝,我在這個問題上學到了很多東西。當我回家時,我會重讀每種擴展方法的文檔。 – Renan

+0

聯盟將刪除重複項,他沒有將其作爲明確的目標。如果沒有重複,那麼你會浪費時間/精力/內存檢查。 'Concat'幾乎與'Union'相同,但沒有重複檢查,似乎是這裏更合適的操作符。 – Servy

+0

@Servy很高興知道。但是,重複測試與平等運營商,對不對?所以具有相同屬性值的兩個對象仍然會評估爲不同的,對嗎? – Renan