【问题标题】:Remove items of list from another lists with criteria使用条件从另一个列表中删除列表项
【发布时间】:2011-05-17 18:43:57
【问题描述】:

我有一个作家名单。

public class Writers{   
    long WriterID { get;set; }
}

我还有两个 Article 类型的列表。

public class Article{
    long ArticleID { get; set; }
    long WriterID { get; set; }
    //and others    
}

所以我的代码是:

List<Article> ArticleList = GetList(1);
List<Article> AnotherArticleList = AnotherList(2);
List<Writers> listWriters = GetAllForbiddenWriters();

我想从ArticleListAnotherArticleList 中删除这些记录,其中WriterIDlistWriters WriterID 匹配。如何在 LINQ 中做到这一点?

【问题讨论】:

    标签: c# .net linq list


    【解决方案1】:

    如果你真的有List&lt;T&gt;,我建议你在构造一组写者ID之后使用List&lt;T&gt;.RemoveAll

    HashSet<long> writerIds = new HashSet<long>(listWriters.Select(x => x.WriterID));
    
    articleList.RemoveAll(x => writerIds.Contains(x.WriterId));
    anotherArticleList.RemoveAll(x => writerIds.Contains(x.WriterId));
    

    如果你确实想使用 LINQ,你可以使用:

    articleList = articleList.Where(x => !writerIds.Contains(x.WriterId))
                             .ToList();
    anotherArticleList = anotherArticleList
                             .Where(x => !writerIds.Contains(x.WriterId))
                             .ToList();
    

    请注意,这会更改 变量,但不会修改现有列表 - 因此,如果有任何其他对同一列表的引用,他们将不会看到任何更改。 (而RemoveAll 修改了现有列表。)

    【讨论】:

    • 由于 articleList 和 anotherArticleList 具有 Article 对象,而 listWriters 具有 Writers 对象,除非重写 Equals 方法以仅将 WriterID 与正确的转换进行比较,因为它看起来不像她有一个共同的由 Article / Writers 实现的接口。
    • 我认为不创建 writerIds 的 HashSet 是可能的。如果你看看我下面的帖子......
    • @bitxwise:是的,可能 - 但我认为我的解决方案更清晰,也更有效,特别是如果有很多作家。 (我个人会使用Any 而不是Exists,但这并不重要。)
    • @Jon - 你仍然会遍历整个 writerList 以制作你的 HashSet - 只是在将它应用于文章列表时再次遍历你的 HashSet,所以我不认为它是更高效...至于更清晰,也许在某种程度上更直观?但是,通过查看我发布的代码,您可以确定它正在从作者存在于 writerList 的文章列表中删除(并且通过 WriterID 做出确定)。
    • @bitxwise:不,因为 HashSet 上的 Contains 不会遍历所有内容。它进行哈希查找,这是 O(1) 而不是 O(n)。您也不必在每次迭代时获取每个 Writer 的属性。就清晰度而言,我认为将“被禁止”的作者视为一个集合而不是一个列表更好,因为顺序并不重要,我们通过 ID 找到他们,所以这就是我们所关心的关于。
    【解决方案2】:
    articlesList.RemoveAll(a => listWriters.Exists(w => w.WriterID == a.WriterID));
    anotherArticlesList.RemoveAll(a => listWriters.Exists(w => w.WriterID == a.WriterID));
    

    【讨论】:

      【解决方案3】:

      你可以使用Except:

      List<car> list1 = GetTheList();
      List<car> list2 = GetSomeOtherList();
      List<car> result = list2.Except(list1).ToList();
      

      【讨论】:

        【解决方案4】:

        我真的不明白你面临的困难是什么......

        为什么不使用简单的 for 循环从列表中过滤/删除数据? (请注意,如果您在编辑/更改迭代对象时进行迭代,则 foreach 循环肯定不起作用)

        for (int i = ArticleList.Count -1; i >= 0; i--)
        {
            for (int j = 0; j < listWriters.Count; j++)
            {
                if (ArticleList[i].WriterId == listWriters[j].WriterID )
                    ArticleList.RemoveAt(i);
            }            
        }
        

        向后迭代技巧解决了“在迭代时删除项目”的范例。

        【讨论】:

        • 感谢您的回答。其实我想要一个 LINQ 解决方案
        • 我很高兴我不必再编写这样的代码了。再见C/C++days 和你好Linq - OMG - 我的眼球在流血:)
        • 人们也不需要用 C++ 编写这样的代码。在 C++ 中,您有 remove_if(很久以前引入)和 lambdas,因此如果在 C++ 中完成,当前接受的答案将是相似的。
        【解决方案5】:

        只是一个设计提示,你的类应该被称为Writer(单数形式),而不是Writers(复数形式)。你列表中的每一项都代表一个作者,对吗?

        【讨论】:

        • 你应该把它放到评论中,因为它不是问题的答案。
        猜你喜欢
        • 1970-01-01
        • 2011-02-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-09-20
        相关资源
        最近更新 更多