2011-05-12 34 views
1

結果集說我有一個稱爲GetCatsByColor方法,該方法採用一種顏色作爲一個字符串,一個方法GetCatsByName這需要一個名稱作爲一個字符串,以及GetCatsByBirthDate採用兩個DateTime演技爲範圍的時間。縮小使用LINQ

現在說我有一個CatFilter類持有名字的List,顏色List和兩個DateTime S,表示「從」日期和時間跨度的「到」日期。我想要做的是創建一個GetFilteredCats方法,其中包含這些Filter對象之一,並返回一組符合給定Filter規範的Cat。

我很難想出一個獲得理想結果的理想方式,理想情況下使用LINQ/lambda表達式。

要做這種連接最好的方法是什麼?我應該看什麼擴展方法?修改foreach循環中的集合通常不可取/可行,所以我的策略是什麼?

+2

效率=性能或潔淨度和易用性? – mellamokb 2011-05-12 21:32:17

+0

我正在尋找一個高性能的解決方案,但如果您有一個優雅的解決方案並不一定是時間複雜度最高的解決方案,那麼我就是所有人。 – 2011-05-12 21:35:25

+0

假設你已經過濾了{{''Garfield'},{'yellow'}}'。你想要所有名爲加菲貓和黃色的貓或名爲加菲貓或黃色的貓嗎? – svick 2011-05-12 22:31:36

回答

1

我通常會做的是在執行實際過濾器之前檢查是否需要過濾器的where子句。當運行時需要評估過濾器時,如果不需要,它將被完全跳過。

public class CatFilter 
{ 
    public List<string> Names = new List<string>(); 
    public List<string> Colors = new List<string>(); 
    public DateTime? BirthDateStartRange = null; 
    public DateTime? BirthDateEndRange = null; 
} 

public List<Cat> GetFilteredCats(CatFilter filter) 
{ 
    List<Cat> result = new List<Cat>(); 

    var query = cats 
     .Where(a => !filter.Names.Any() || filter.Names.Contains(a.Name)) 
     .Where(a => !filter.Colors.Any() || filter.Colors.Contains(a.Color)) 
     .Where(a => filter.BirthDateStartRange == null || a.DateOfBirth >= filter.BirthDateStartRange) 
     .Where(a => filter.BirthDateEndRange == null || a.DateOfBirth <= filter.BirthDateEndRange); 

    result.AddRange(query); 
    return result; 
} 

,然後調用它像編碼這樣的

cats.Add(new Cat("Felix", "Black", DateTime.Today.AddDays(-1))); 
cats.Add(new Cat("Garfield", "Orange", DateTime.Today.AddDays(-10))); 

CatFilter filter = new CatFilter(); 
filter.Names.Add("Garfield"); 

List<Cat> result = GetFilteredCats(filter); 
0

正確的方式做,這就是讓法GetFilteredCats,接受你的過濾器和throught LINQ組成返回正確的貓:

IEnumerable<Cat> cats = //.. get all cats here 

if (filter.FilterByColor) 
    cats = cats.Where(c=>c.Color = filter.Color); 

if (filter.FilterByName) 
    cats = cats.Where(c=>c.Name = filter.Name); 

if (filter.FilterByDate) 
    cats = cats.Where(c=>c.Date > filter.FromDate && c.Date < filter.ToDate) 

return cats.ToList(); // finally filter data and return them. 

在性能情況。我不認爲這可以通過不同的方式來完成。但是當你開始打數以萬計的貓時,這會成爲問題。在這一點上,應該使用數據庫。這些都有巧妙的索引和聚類,爲您提供方便。

+0

我已經想到了這一點,但我想避免整個「讓所有的貓」的一部分。這是一個數據庫存儲庫。 – 2011-05-12 21:40:24

+0

然後這樣說。然後你有完全相同的方法,但不是IEnumerable你使用IQueryable:http://stackoverflow.com/questions/5881107/how-can-i-build-entity-framework-queries-dynamically/5882243#5882243 – Euphoric 2011-05-12 21:43:18

0

像這樣的事情應該工作,請注意這不是測試

List<string> names = new List<string>(); 
      List<Color> colors = new List<Color>(); 
      List<DateTime> dobs = new List<DateTime>(); 

      List<cat> cats = new List<cat>(); 


      var filtered = from c in cats 
          join n in names on c.name equals n 
          join cl in colors on c.color equals cl 
          join db in dobs on c.dob equals db 

          select c; 

你也可以有一些名單有兩個日期,在這種情況下,你需要把WHERE條件,其中c.dob < = date1 & & c.dob> = date2,或類似的東西。 希望這有助於。

0

您可以使用表達式樹。當一個CatFilter對象傳遞給你的GetFilteredCats方法時,根據在這個對象上設置的屬性,你生成表達式(也就是下面的僞代碼),你可以連接它並用它來構建一個完整的LINQ查詢。

喜歡的東西:

Expression catFilter = 
from cat in Cats 
    where <Expression> and <Expression> and ... 
select cat 

然後簡單地編譯(Expression.Compile)和執行。