2011-02-23 110 views
1

我有以下代码:排除从Linq查询排除一切结果

 public IList<Tweet> Match(IEnumerable<Tweet> tweetStream, IList<string> match, IList<string> exclude) 
    { 
     var tweets = from f in tweetStream 
        from m in match 
        where f.Text.ToLowerInvariant().Contains(m) 
        select f; 

     var final = from f in tweets 
        from e in exclude 
        where !f.Text.ToLowerInvariant().Contains(e.ToLowerInvariant()) 
        select f; 

     return final.Distinct().ToList<Tweet>(); 
    } 

我已经建立还没有包括final结果集,现在已经幸福地匹配我的测试已添加排除,如果IList<string>exclude为空,则删除所有项目。

所以这个测试通过,因为它应该:

 [TestMethod] 
    public void Should_exclude_items_from_exclude_list() 
    { 
     IEnumerable<Tweet> twitterStream = new List<Tweet> 
               { 
                new Tweet("I have a Mazda car"), 
                new Tweet("I have a ford"), 
                new Tweet("Mazda Rules"), 
                new Tweet("My Ford car is great"), 
                new Tweet("My renault is brill"), 
                new Tweet("Mazda cars are great") 
               }; 
     IList<string> matches = new List<string>{"mazda","car"}; 
     IList<string> exclude = new List<string>{"ford"}; 

     Matcher target = new Matcher(); 
     IList<Tweet> actual = target.Match(twitterStream, matches, exclude); 

     Assert.AreEqual(3, actual.Count);    
    } 

但现在测试失败:

 [TestMethod] 
    public void Should_match_items_either_mazda_or_car_but_no_duplicates() 
    { 
     IEnumerable<Tweet> twitterStream = new List<Tweet> 
               { 
                new Tweet("I have a Mazda car"), 
                new Tweet("I have a ford"), 
                new Tweet("Mazda Rules"), 
                new Tweet("My Ford car is great"), 
                new Tweet("My renault is brill"), 
                new Tweet("Mazda cars are great") 
               }; 
     IList<string> matches = new List<string>{"mazda","car"}; 
     IList<string> exclude = new List<string>(); 

     Matcher target = new Matcher(); 
     IList<Tweet> actual = target.Match(twitterStream, matches, exclude); 

     Assert.AreEqual(4, actual.Count); 
    } 

我知道我失去了一些东西很简单,但在代码盯着一个小时后,它不会来到我身边。

回答

5

嗯,我知道为什么它的失败:它的这个子句:

from e in exclude 

这将是一个空的集合,所以没有条目连打where子句。

这里的另一种方法:

var final = from f in tweets 
      let lower = f.Text.ToLowerInvariant() 
      where !exclude.Any(e => lower.Contains(e.ToLowerInvariant()) 
      select f; 

虽然我认为msarchet的方式为好,这一块的好处是,它只是结束了评估tweetStream一次 - 所以即使是从网络上读取或做另外一些痛苦,你不必担心。如果可能(并且方便),我尽量避免多次评估LINQ流。

当然,你也可以使整个事情一个查询很容易:

var tweets = from f in tweetStream 
      let lower = f.Text.ToLowerInvariant() 
      where match.Any(m => lower.Contains(m.ToLowerInvariant()) 
      where !exclude.Any(e => lower.Contains(e.ToLowerInvariant()) 
      select f; 

我认为更清洁,说实话:)

+0

@JonSkeet,其实我打你的答案,世界即将结束。 :D – msarchet 2011-02-23 22:25:02

+1

@msarchet:不公平,我的妻子需要帮忙评价一件衣服:)(而且我更喜欢我的答案,因为我现在指定的原因。) – 2011-02-23 22:26:46

+0

@JonSkeet,是的,它是我的干净版 – msarchet 2011-02-23 22:27:23

1

所以发生是这样的:

var final = from f in tweets 
      from e in exclude 
      where !f.Text.ToLowerInvariant().Contains(e.ToLowerInvariant()) 
      select f; 

由于第二从是空的,如果我是正确的语句的其他部分并没有进行评估,所以你的选择是永远不会发生的事情。

尝试这样做是这样,而不是

var excludeTheseTweet = from f in tweets 
         from e in exclude 
         where f.Text.ToLowerInvariant().Contains(e.ToLowerInvariant()) 
         select f; 

return tweets.Except(excludeTheseTweets).Distinct().ToList<Tweet>(); 

这样会得到鸣叫的列表exculde(所以如果有什么可以排除它不会得到任何东西),然后它会删除这些项目形成原始列表。