2011-05-12 33 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)和执行。