简体   繁体   English

使用Linq在两个列表之间进行规范化的最佳方法是什么?

[英]What's the best way to normalize between two lists using Linq?

Given two IEnumerable instances in C# (call them a and b), what's the best way to remove all values in a that are not in b and add all values of b that are not in a? 给定C#中的两个IEnumerable实例(分别称为a和b),最好的方法是删除a中所有不在b中的值,然后将b中所有不在a中的值相加?

I know I could just set a = b, normally, but this is ultimately for persisting to the DB via Entity Framework CodeFirst in an MVC application so there's some wonkiness of state to watch out for. 我知道我通常可以设置a = b,但这最终是为了通过MVC应用程序中的Entity Framework CodeFirst持久存储到数据库,因此需要警惕。 In fact, we're talking about updating a record based on stuff posted from the client. 实际上,我们正在谈论根据客户端发布的内容更新记录。

The closest that seems to work involves about for foreach loops, one to iterate the 'a' list and populate a collection of 'items to be removed', another to iterate the 'b' list to identify the 'items to be added', and then one each on the 'items to be removed' and 'items to be added' collections to add and remove items, respectively (since you can't modify the 'a' collection while you're iterating on it. 似乎最接近的工作涉及foreach循环,一个循环访问“ a”列表并填充“待删除的项目”的集合,另一个循环访问“ b”列表以标识“要添加的项目”,然后分别在“要删除的项目”和“要添加的项目”集合中分别添加和删除项目(因为在迭代时无法修改“ a”集合)。

That feels clunky, though; 但是,这感觉很笨拙。 is there a better way? 有没有更好的办法?

UPDATE For clarity, I'll make an example. 更新为清楚起见,我将举一个例子。 Let's say I have an entity I fetch from the DB which represents a blog Post (since that example never gets tired...) and said Post has a collection of Tags. 假设我有一个从数据库中获取的实体,该实体代表一个博客Post(因为该示例永远不会感到疲倦...),并且说Post具有标签的集合。 From the client, I get a list of Tags that should be now the 'canonical' list of tags, but none of them are entities, it's just an in-memory collection. 从客户端,我得到了一个标签列表,这些标签现在应该是标签的“规范”列表,但是它们都不是实体,它只是一个内存中的集合。 What I want to do is ensure that Post.Tags matches the tags being posted by the client, without creating duplicate tags in the database. 我要做的是确保Post.Tags与客户端发布的标签匹配,而不在数据库中创建重复的标签。

You can use Intersect , Concat and Except : 您可以使用IntersectConcatExcept

a = a.Intersect(b).Concat(b.Except(a));

Intersect returns items that exist in both collections, so a.Intersect(b) will give you all items that are in a and b . Intersect返回两个集合中都存在的项目,因此a.Intersect(b)将为您提供aba所有项目。

Except returns elements that are in first collection, but not in the other, so b.Except(a) returns elements that are in b but not in a . Except返回第一个集合中的元素,但不返回另一个集合中的元素,因此b.Except(a)返回b但不在a元素。

Concat concatenates these two collections. Concat将这两个集合连接在一起。

But I don't really get your questions, so I'm not sure it's what you're looking for. 但是我真的没有收到您的问题,所以我不确定这不是您要的内容。

It sounds like your enumerable a is actually a list, so I did it this way: 听起来您的可枚举a实际上是一个列表,所以我这样做是这样的:

var a = new List<int>() { 1, 2, 3, };
var b = new List<int>() { 1, 3, 4, 5, };

foreach (var x in a.Except(b).ToArray())
{
    a.Remove(x);
}

foreach (var x in b.Except(a).ToArray())
{
    a.Add(x);
}

At the end a has the same elements as b . 最后, ab具有相同的元素。

However, you need to be careful if you have duplicates in b . 但是,如果b有重复项,则需要小心。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM