2012-09-13 48 views
4

我要選擇使用myFilters的用於過濾從MyCollection的元素:使用LINQ,如何有條件地選擇一些項目,但沒有條件時全部選中?

var myFilters = new List<string> {"111", "222"}; 
var myCollection = new List<SomeClass> { 
         new SomeClass ("111"), 
         new SomeClass ("999") 
        }; 

from filter in myFilters 
from item in myCollection 
where item.Name == filter 
select item 

將返回 「111」 項目。

但是,如果myFilters爲空,我想返回myCollection中的所有項目。

var myFilters = new List<string>(); 
var myCollection = new List<SomeClass> { 
          new SomeClass ("111"), 
          new SomeClass ("999") 
        }; 

// Here's where I'm lost... 
from filter in myFilters 
from item in myCollection 
where item.Name == filter 
select item 

將返回所有項目(「111」和「999」)。

+0

您將無法使用單個查詢執行此操作,因爲類型不同。在一種情況下,您將返回一個IEnumerable ,而在另一個情況下,您將返回一個IEnumerable 。如果你的查詢以選擇item.Name而不是選擇項目結束,事情會有所不同。 – itsme86

+0

如果本地變量名稱被引用,則「第一個集合」和「第二個集合」會更清晰。例如:「但是,當myFilters爲空時,我想不經過濾就返回myCollection中的所有項目。」 – devgeezer

+0

你說得對。我想現在更清楚了。 –

回答

7

如果這些集合將會很大,那麼我建議使用連接。它看起來像這樣:

var result = 
    myFilters.Any() ? 
     from item in myCollection 
     join filter in myFilters 
     on item.Name equals filter into gj 
     where gj.Any() 
     select item 
    : myCollection; 

使用連接的機會很容易被忽略。當列表遠程大時,這種連接方法將優於包含方法。如果它們很小並且性能可以接受,那麼請使用最清晰的那個。

+0

簡單而重要。大!謝謝 –

1

您將能夠做的最好的事情是將濾鏡投影到SomeClass中。喜歡的東西:

var results = myCollection.Any() ? 
    myCollection.Where(item => myFilters.Contains(item.Name)) : 
    myFilters.Select(f => new SomeClass (f)); 
+0

唉,不行。嘗試在linqpad –

+0

它適用於我在VS2010。 – itsme86

+0

請注意,這不是來自'myCollection'的已過濾實例的子集,而是從匹配的'myFilters'值創建的新SomeClass實例的投影。 – devgeezer

0

試試這個:

var result = myCollection.Where(s => !myFilters.Any() || 
            myFilters.Contains(s.Name)); 
//EDIT: commented these lines..based on comment by @Servy 
//var result = myCollection.Where(s => myFilters.Count == 0 || 
//          myFilters.Contains(s.Name)); 

也許這將是更好的計數過濾收集一次:

bool isFilterEmpty = !myFilters.Any(); 
//bool isFilterEmpty = myFilters.Count == 0; //...or like this 
var result = myCollection.Where(s => isFilterEmpty || 
            myFilters.Contains(s.Name)); 

編輯

我甚至會說,@ itsme86的答案是正確的,但是,我猜,他有騙局融合您的收藏。所以他的答案應該看起來像這樣:

var results = myFilters.Any() 
       ? myCollection.Where(item => myFilters.Contains(item.Name)) 
       : myCollection; 
+2

而不是'Count()== 0',你可以使用'Any()'。它不僅會表現得更好(它只需要獲得第一項知道是否有需要獲取每個項目來獲得計數),但它也在語義上意味着你正在嘗試做什麼。 – Servy

+0

@Servy其實我的答案中有'Any'變體。無論如何,感謝澄清。 – horgh

+0

從where謂詞中提取「Any()」是一個很好的性能表現。關於在謂詞中保留「Any()」的好處在於,如果查詢被保留並且「myFilters」或「myCollection」列表被更改(例如,清除,添加項目,刪除項目),則後續迭代將會提供更新的結果。 – devgeezer

0

這個怎麼樣?

var myFilters = new List<string>(); 
var myCollection = new List<SomeClass> {new SomeClass ("111"), new SomeClass ("999")}; 

// Here's where I'm lost... 
from filter in myFilters 
from item in myCollection 
where item.Name == filter || !myFilters.Any() 
select item 

從兩個集合中選擇根據where子句執行連接。上面的連接條件表示加入item.Name等於過濾器,或者如果沒有可用的過濾器,則選擇它。

3
var result = myCollection 
        .Where(i => (!myFilters.Any() || myFilters.Contains(i.Name)));