连接两个列表,比较它们的元素属性

本文关键字:比较 属性 元素 列表 两个 连接 | 更新日期: 2023-09-27 18:14:15

public class Person()
    {
    int ID;
    string Name;
    DateTime ChangeDate
    } 

var list1 = new List<Person>
    {
        new Person { ID= 1, Name = "Peter", ChangeDate= "2011-10-21" },
        new Person { ID= 2, Name = "John",  ChangeDate= "2011-10-22" },
        new Person { ID= 3, Name = "Mike",  ChangeDate= "2011-10-23" },
        new Person { ID= 4, Name = "Dave",  ChangeDate= "2011-10-24" }
    };
 var list2 = new List<Person>
    {
        new Person { ID= 1, Name = "Pete",  ChangeDate= "2011-10-21" },
        new Person { ID= 2, Name = "Johny", ChangeDate= "2011-10-20" },
        new Person { ID= 3, Name = "Mikey", ChangeDate= "2011-10-24" },
        new Person { ID= 5, Name = "Larry", ChangeDate= "2011-10-27" }
    };

作为输出,我想让list1 + list2 =

    Person { ID= 1, Name = "Peter", ChangeDate= "2011-10-21" },
    Person { ID= 2, Name = "John",  ChangeDate= "2011-10-22" },
    Person { ID= 3, Name = "Mikey", ChangeDate= "2011-10-24" },
    Person { ID= 4, Name = "Dave",  ChangeDate= "2011-10-24" }
    Person { ID= 5, Name = "Larry", ChangeDate= "2011-10-27" }

算法是这样的。加入两个列表。如果列表中的元素具有相同的ID,则用ChangeDate比较它们,并取日期较大的那个。如果ChangeDate相等,取其中任何一个,但不能两个都取。也许连接两个列表比使用lambda过滤它们更容易。我试过了,但总是得到一些丑陋的代码:/

有人知道吗?

连接两个列表,比较它们的元素属性

LINQ

var q = from person in list1.Concat(list2)
        group person by person.ID into g
        select g.OrderByDescending(p => p.ChangeDate).First();

合并两个按降序排序的列表。现在需要取排序列表中每个id第一次出现的值

这样怎么样?

using System;
using System.Collections.Generic;
using System.Linq;
public class Person
{
    public int ID;
    public string Name;
    public DateTime ChangeDate;
}
public class PersonComparer : IEqualityComparer<Person>
{
    public bool Equals(Person p1, Person p2)
    {
        return p1.ID == p2.ID;
    }
    public int GetHashCode(Person p)
    {
        return p.ID.GetHashCode();
    }
}
class Program
{
    static void Main(string[] args)
    {
        var list1 = new List<Person>
        {
            new Person { ID = 1, Name = "Peter", ChangeDate = DateTime.Parse("2011-10-21") },
            new Person { ID = 2, Name = "John",  ChangeDate = DateTime.Parse("2011-10-22") },
            new Person { ID = 3, Name = "Mike",  ChangeDate = DateTime.Parse("2011-10-23") },
            new Person { ID = 4, Name = "Dave",  ChangeDate = DateTime.Parse("2011-10-24") }
        };
        var list2 = new List<Person>
        {
            new Person { ID = 1, Name = "Pete",  ChangeDate = DateTime.Parse("2011-10-21") },
            new Person { ID = 2, Name = "Johny", ChangeDate = DateTime.Parse("2011-10-20") },
            new Person { ID = 3, Name = "Mikey", ChangeDate = DateTime.Parse("2011-10-24") },
            new Person { ID = 5, Name = "Larry", ChangeDate = DateTime.Parse("2011-10-27") }
        };
        var pc = new PersonComparer();
        var combined = list1.Join(list2, p => p.ID, p => p.ID, (p1,p2) => p2.ChangeDate > p1.ChangeDate ? p2 : p1)
                            .Union(list1.Except(list2, pc))
                            .Union(list2.Except(list1, pc));
        foreach(var p in combined)
        {
            Console.WriteLine(p.ID + " " + p.Name + " " + p.ChangeDate);
        }
    }
}

您可以将它们连接并排序,然后得到不同的值:

class PersonIdEqualityComparer : IEqualityComparer<Person>
{
    public bool Equals(Person x, Person y)
    {
        return x.ID == y.ID;
    }
    public int GetHashCode(Person person)
    {
        return person.ID;
    }
}
var result = list1.Concat(list2)
    .OrderByDescending(i => DateTime.Parse(i.ChangeDate)) // Most recent first
    .Distinct(new PersonIdEqualityComparer())
    ;

这假设Distinct将从每个集合中取出遇到的第一个项目,而不是任意的项目。考虑到它可能只是在遍历集合时将它们插入HashSet,这对我来说似乎是合理的。

也不做错误检查。如果任何值可能为空,或者ChangeDate可能无效,则此代码将抛出异常。如果这可能是一个问题,我建议您在传入之前检查您的数据,并且您在PersonIdEqualityComparer类中进行错误检查。