使用LINQ合并两个IEnumerable

4

我有如下类

public class Application
{
    public int Id { get; set; }

    public int Version { get; set; }

    (...)
}

我有以下IEnumerable<Application>

IEnumerable<Application> applications1 = new List<Application>
{
    new Application {Id = 1, Version = 1},
    new Application {Id = 2, Version = 1},
    new Application {Id = 3, Version = 3}
};

IEnumerable<Application> applications2 = new List<Application>
{
    new Application {Id = 1, Version = 2},
    new Application {Id = 3, Version = 2}
    new Application {Id = 4, Version = 1}
};

如何使用 LINQ 将它们合并为一个单一的 IEnumerable<Application>,同时确保如果两个 Applications 具有相同的 Id,则只添加具有最高 Version 的一个到新的 IEnumerable<Application> 中,最终生成的 IEnumerable 与以下内容等效:
IEnumerable<Application> final = new List<Application>
{
    new Application {Id = 1, Version = 2},
    new Application {Id = 2, Version = 1},
    new Application {Id = 3, Version = 3},
    new Application {Id = 4, Version = 1}
}

3
@PavelAnikhouski这样做对版本没有任何影响。因此,哪个版本会存活下来是完全随机的。 - MakePeaceGreatAgain
@PavelAnikhouski,这并没有真正回答我的问题,因为他的对象实际上是相等的,而我的不是,但还是谢谢你提出来。 - cogumel0
这个回答解决了你的问题吗?合并两个IEnumerable<T> - Heretic Monkey
3个回答

5

您可以使用GroupBy与通过Aggregate选择组中的最大值进行组合:

IEnumerable<Application> final = applications1
    .Concat(applications2)
    .GroupBy(a => a.Id)
    .Select(g => g.Aggregate((acc, curr) => acc.Version > curr.Version ? acc: curr))
    .ToList();

1
为什么不直接写这样的东西?
var result = applications1
    .Concat(applications2).GroupBy(x => x.Id)
    .Select(g => new Application { Id = g.Key, Version = g.Max(a => a.Version) });

你需要将两个集合连接起来,按Id分组,然后选择新的Application实例作为组键的Id和最大Version
如果你不想创建新的Application实例,下面的代码可能会有所帮助,它会查找每个组的最大Version并返回具有最大Version值的Application
var result = applications1
    .Concat(applications2).GroupBy(x => x.Id)
    .Select(g =>
    {
        var maxVersion = g.Max(a => a.Version);
        return g.First(a => a.Version == maxVersion);
    });

我知道在给定的示例中这会起作用,但它假设类只有两个属性并且都有setter,以便可以构造一个新对象。不幸的是,在这里情况并非完全如此。尽管如此,我仍然会点赞,因为它在给定的示例中确实有效。 - cogumel0
@cogumel0 是的,我理解你的例子。如果这里有更多的属性,你应该考虑如何管理它们 - 添加到分组中,使用第一个/最后一个/平均值/最大值等等。 - Pavel Anikhouski
我想说的是,我认为有更好的方法而不需要重新创建对象。 - cogumel0
@cogumel0 我明白你的意思了,我添加了另一个代码片段,它不需要重新创建对象。 - Pavel Anikhouski

1
一种更加过程化的方法是:

var concat = applications1.Concat(applications2)
    .ToArray();

var final = concat
    .GroupBy(a => a.Id)
    .Select (g => new
    {
        ApplicationId = g.Key,
        MaxVersion = g.Max(i => i.Version)
    })
    .Select(i => concat.FirstOrDefault(
        existing => existing.Id == i.ApplicationId && 
                    existing.Version == i.MaxVersion))
    .ToList();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接