linq 将3个IELTS列表合并< Application>为一个

wswtfjt7  于 2023-11-14  发布在  其他
关注(0)|答案(3)|浏览(95)

我把我的问题简化了

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

字符串
我的三个清单:

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

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

IEnumerable<Application> applications3 = new List<Application>
{
    new Application {Id = 1, Version = 5, Status = 1},
    new Application {Id = 2, Version = 0, Status = 1},
    new Application {Id = 3, Version = 6, Status = 1}
};


我想制作这个:

IEnumerable<Application> applications4 = new List<Application>
{
    new Application {Id = 1, Version = 5, Status = 2},
    new Application {Id = 2, Version = 2, Status = 2},
    new Application {Id = 3, Version = 6, Status = 1}
};


即一个列表,其中的版本和状态的最高值。我已经尝试与LINQ,但我没有得到它。
我最好的是这个,但它只是得到最高版本。我不明白我怎么做时,有2个属性可供选择:

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

dw1jzc5e

dw1jzc5e1#

您应该使用Max()从分组属性中获取最大值。

IEnumerable<Application> applications4 = applications1
    .Concat(applications2)
    .Concat(applications3)
    .GroupBy(a => a.Id)
    .Select(g => new Application
            {
                Id = g.Key,
                Version = g.Max(x => x.Version),
                Status = g.Max(x => x.Status)
            })
    .ToList();

字符串

bgibtngc

bgibtngc2#

你的问题忽略了一个非常重要的问题-哪个属性(版本或状态)更重要?
我假设版本更重要,并创建了一个自定义比较器来对结果进行排序。基本上我想要的是根据应用程序ID对项目进行 * 分组 *,然后获得最高的结果。我使用了自定义比较器来获得它。如果你不想使用比较器,你可以随时将其更改为:.Select(x => x.OrderByDescending(x => x.Version).ThenBy(x => x.Status).First());

internal class Program
    {
        static async Task Main(string[] args)
        {
            IEnumerable<Application> applications1 = new List<Application>
            {
                new Application {Id = 1, Version = 1, Status = 1},
                new Application {Id = 2, Version = 1, Status = 1},
                new Application {Id = 3, Version = 3, Status = 1}
            };

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

            IEnumerable<Application> applications3 = new List<Application>
            {
                new Application {Id = 1, Version = 5, Status = 1},
                new Application {Id = 2, Version = 0, Status = 1},
                new Application {Id = 3, Version = 6, Status = 1}
            };

// you can use OrderByDescending().First() for applications using EF lower than 6.0.0
            var applications4 = applications1.Union(applications2).Union(applications3)
                .GroupBy(x => x.Id)
                .Select(x => x.MaxBy(x => x, new VersionStatusComparer()));

            foreach (var item in applications4)
            {
                Console.WriteLine("Id: {0} Version: {1} Status: {2}", item.Id, item.Version, item.Status);
            }
        }
    }

    internal class VersionStatusComparer : IComparer<Application>
    {
        public int Compare(Application? x, Application? y)
        {
            var versionResult = CompareVersion(x.Version, y.Version);
            if (versionResult == 0)
            {
                return CompareStatus(x.Status, y.Status);
            }

            return versionResult;
        }

        private int CompareVersion(int xVersion, int yVersion)
        {
            if (xVersion > yVersion)
            {
                return 1;
            }
            else if (xVersion < yVersion)
            {
                return -1;
            }

            return 0;
        }

        private int CompareStatus(int xStatus, int yStatus)
        {
            if (xStatus > yStatus)
            {
                return 1;
            }
            else if (xStatus < yStatus)
            {
                return -1;
            }

            return 0;
        }
    }
}

字符串

vc6uscn9

vc6uscn93#

这里有一个更面向OOP的方法,但我希望它看起来更明确。如果你需要一个更复杂的场景,你可以更新Merge逻辑。它的复杂度为O(n)(n个元素的数组需要n个“陡峭”才能完成),并使用字典:

public class Application
{
    public int Id { get; set; }
    public int Version { get; set; }
    public int Status { get; set; }
    public bool Merge(Application app){
        if(app.Id != Id) return false;
        this.Version = Math.Max(app.Version, this.Version);
        this.Status = Math.Max(app.Status, this.Status);
        return true;
    }
}
//...
IEnumerable<Application> applications4 = new List<Application>();
Dictionary<int,Application> res = new Dictionary<int,Application>();
        
foreach( var app in applications1.Concat(applications2).Concat(applications3) ){
  // existing value, then update
  if( res.TryGetValue( app.Id, out Application appToProceed )) appToProceed.Merge(app);
  // new id value, then add
  else res.Add(app.Id,app);
}
//
applications4 = res.Values.ToList();

字符串
关于基准测试结果,它是关于ns的,所以就像一些信息一样:

| Method                                        | Mean       | Error   | StdDev  | Gen0   | Allocated |
|---------------------------------------------- |-----------:|--------:|--------:|-------:|----------:|
| Benchmark_Using_Dictionary__3List_1000Element |   226.8 ns | 3.03 ns | 2.84 ns | 0.0780 |     408 B |
| Benchmark_Using_LINQ__3List_1000Element       |   299.7 ns | 4.04 ns | 3.59 ns | 0.1040 |     544 B |
| Benchmark_Using_Dictionary__3List_3Element    |   652.5 ns | 2.09 ns | 1.85 ns | 0.1125 |     592 B |
| Benchmark_Using_LINQ__3List_3Element          | 1,631.4 ns | 8.12 ns | 7.59 ns | 0.2842 |    1488 B |


(3列表表示app1 + app2 + app3,1000元素表示每个应用程序有1000个ID可供使用)

相关问题