排除Linq查询的结果,排除排除列表为空时的所有内容

时间:2011-02-23 22:16:47

标签: c# linq-to-objects

我有以下代码:

        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);
    }

我知道我错过了一些非常简单的东西,但是在盯着代码一小时之后它就没有找到我。

2 个答案:

答案 0 :(得分: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;

我认为即使更清洁,老实说:)

答案 1 :(得分: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>();

这样就会得到一条推文列表(所以如果没有什么可以排除它就不会得到任何东西)然后它将从原始列表中删除这些项目。