2011-02-23 69 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(所以如果有什麼可以排除它不會得到任何東西),然後它會刪除這些項目形成原始列表。