如何合并两个 IEnumerables?

Posted

技术标签:

【中文标题】如何合并两个 IEnumerables?【英文标题】:How to merge two IEnumerables? 【发布时间】:2022-01-07 05:41:30 【问题描述】:

我有两个 Enumberable 列表:list1 和 list2 我想从 list2 中获取一些东西并根据条件在 list1 中更新它

例如:list1.Id 表示例如 1、2、3、4、5 等。 list2.Id 有 3, 4 我需要比较这些 Id 并从 list2 中获取与 list1.Id 匹配的其他字段(例如名称、主题)(在本例中为 3 和 4)并将其复制到 list1 其他字段(名称、主题)

列表1:

Id Name Subject
1 N1 S1
2 N2 S2
3
4
5 N5 S5

列表2:

Id Name Subject
3 N3 S3
4 N4 S4

所需结果:

Id Name Subject
1 N1 S1
2 N2 S2
3 N3 S3
4 N4 S4
5 N5 S5

【问题讨论】:

枚举是在编译过程中创建的,在执行过程中不能修改,或者我误解了一些东西 @Frenchy 他们在谈论可枚举序列,而不是 enum 定义 类似var result = enum1.Where(item => !string.IsNullOrEmpty(item)).Union(enum2); 你试过什么?通常的方法:选择具有相同属性+属性类型的(匿名)类对象。这意味着:将枚举值转换为整数。 您已标记实体框架:您需要在数据库中执行此操作,还是在内存中可以接受? 【参考方案1】:

不太清楚你需要什么。我假设您需要根据 enum2 更新 enum1 中的数据,在这种情况下这样做:

foreach(var item in enum2)

    var itemToUpdate = enum1.SingleOrDefault(x => x.Id == item.Id);
    if (itemToUpdate == null) continue;
    itemToUpdate.Name = item.Name;
    itemToUpdate.Subject = item.Subject;

【讨论】:

【参考方案2】:

假设您的课程主题如下:

 class Suabject
    
        public int id;
        public string name;
        public string Subject;
    

你有两个列表如下:

    List<Suabject> enum1 = new List<Suabject>();
    List<Suabject> enum2 = new List<Suabject>();

如果你想合并它们,你所做的基本上是遍历 enum2 中的所有项目并检查项目是否存在于 enum1 中然后你更新它。如果没有,您可以将其添加到列表中。如下:

  foreach (var item in enum2)
            
                var s = enum1.FirstOrDefault(x=> x.id == item.id);
                if(s != null)
                
                    s.name = item.name;
                    s.Subject = item.Subject;
                
                else
                    enum1.Add(s);
            

这样,enum1 将是两者的合并列表。

【讨论】:

感谢您的回复。所有三个答案都解决了目的,但可以在没有 foreach 的情况下完成吗? @RaghavendraHG 请注意,使用 FirstOrDefault(...) 的答案具有 O(n^2) 复杂性,并且随着您使两个列表变大而扩展性会更差(尽管对于小数字并不重要元素) @canton7 你会推荐什么? 任何使用恒定时间查找来查找给定 ID 的匹配项的东西。 Oliver 的回答是使用 GroupBy 来完成的,但您也可以使用 Dictionary【参考方案3】:

this怎么样?

var listOne = new[]

    new Entity  Id = 1, Name = "N1", Subject = "S1" ,
    new Entity  Id = 2, Name = "N2", Subject = "S2" ,
    new Entity  Id = 3 ,
    new Entity  Id = 4 ,
    new Entity  Id = 5, Name = "N5", Subject = "S5" ,
;

var listTwo = new[]

    new Entity  Id = 3, Name = "N3", Subject = "S3" ,
    new Entity  Id = 4, Name = "N4", Subject = "S4" ,
;

// Join to lists by using 1:1 relationship
var pairs = listOne.Join(listTwo, entity => entity.Id, entity => entity.Id, (one, two) => (one, two));

foreach (var pair in pairs)

    // Update first name, if empty
    if(string.IsNullOrEmpty(pair.one.Name))
        pair.one.Name = pair.two.Name;

    // Update first subject, if empty
    if(string.IsNullOrEmpty(pair.one.Subject))
        pair.one.Subject = pair.two.Subject;


// Save and show elements
foreach (var item in listOne)

    Console.WriteLine(JsonConvert.SerializeObject(item));

【讨论】:

【参考方案4】:

如果您正在寻找没有 Foreach 的解决方案,您是否想过在这部分使用字典,将键设置为对象的 id,将值设置为对象本身。

Dictionary<int, ObjectType> dictA = new Dictionary<int, ObjectType>();

你在哪里添加这样的值:

dictA.Add(object.Id, object);

然后你就可以像这样在没有 Foreach 的情况下进行合并:

dictA = dictA.Concat(dictB.Where(b => !dictA.ContainsKey(b.Key))).ToDictionary(b => b.Key, b => b.Value);

这样,dictB 被合并到 dictA 中。如果您希望发生相反的情况,只需反转值即可。

【讨论】:

以上是关于如何合并两个 IEnumerables?的主要内容,如果未能解决你的问题,请参考以下文章

C#中的IEnumable与IEnumator接口的简单理解

按值比较迭代类型(IEnumerables及其亲属)(以检查相等性)

IQuerable与IEnumable的区别

IEnumable和yield

将两个列表映射到 C# 中的字典中

InvalidCastException:无法将“System.Collections.Generic.List”类型的对象转换为 System.Collections.Generic.IEnumer