C# 添加列表<&燃气轮机;转到另一个列表<&燃气轮机;通过过滤

C# 添加列表<&燃气轮机;转到另一个列表<&燃气轮机;通过过滤,c#,.net,list,C#,.net,List,我有一个模型课: public class Person { public int Id { get; set; } public string Name { get; set; } } 当我添加两个列表时: List<Person> people1 = new List<Person> { new Person() { Id = 1, Name = "Name1" }, new Person() { Id = 2, Name = "N

我有一个模型课:

public class Person 
{
    public int Id { get; set; }
    public string Name { get; set; }
}
当我添加两个列表时:

List<Person> people1 = new List<Person> {
    new Person() { Id = 1, Name = "Name1" },
    new Person() { Id = 2, Name = "Name2" },
    new Person() { Id = 3, Name = "Name3" },
};

List<Person> people2 = new List<Person> {
    new Person() { Id = 1, Name = "Name1" },
    new Person() { Id = 4, Name = "Name4" },
    new Person() { Id = 5, Name = "Name5" },
};

people1.AddRange(people2);
List people1=新列表{
new Person(){Id=1,Name=“Name1”},
newperson(){Id=2,Name=“Name2”},
new Person(){Id=3,Name=“Name3”},
};
列表人2=新列表{
new Person(){Id=1,Name=“Name1”},
newperson(){Id=4,Name=“Name4”},
newperson(){Id=5,Name=“Name5”},
};
people1.AddRange(people2);
如果
people2
中的
person
people1
中具有相同的
id
。我如何才能做到这一点?

您可以很容易地使用LINQ实现这一点,但效率低下:

people1.AddRange(people2.Where(p2=>!people1.Any(p1=>p1.Id==p2.Id));
或者您可以先创建一组ID:

HashSet-people1id=newhashset(people1.Select(p1=>p1.Id));
people1.AddRange(people2.Where(p2=>!people1id.Contains(p2.id));
第一种方法显然更简单,但如果列表变大,它可能会变慢,因为对于
people2
中的每个元素,它将查看
people1
中的每个元素

如果
people1
很大,则第二种方法的速度会明显加快。如果
people2
很大,则您不会得到太多好处。例如,如果
people1
只包含几个人,则在哈希集中查找ID不会比在列表中查找快多少

不过,你可以采取完全不同的方法。如果你让你的
Person
类型基于ID实现
IEquatable
,或者创建一个这样做的
IEqualityComparer
,如果你不太需要修改现有列表,那么你就需要“两个列表的联合”,如果您不关心顺序,并且如果每个列表中的所有条目都是唯一的,或者您不介意删除重复项,则可以使用:

//如果需要,请将比较器指定为另一个参数。
//如果需要列表,可以调用ToList查看结果。
var union=people1.union(people2);
(该解决方案有很多条件,但它们很可能都是有效的。)

您可以将运算符用于自定义
IEqualityComparer
。这将创建一个新列表,它是其他2个条件的组合。实现customer IEqualityComparer可以让您控制构成相同记录的内容

var allPeople = people1.Union(people2, new PersonComparer());

public class PersonComparer : IEqualityComparer<Person>
{
  public bool Equals(Person x, Person y)
  {
    // ommited null checks etc
    return x.Id == y.Id;
  }

  public int GetHashCode(Person obj)
  {
    // ommited null checks etc
    obj.Id.GetHashCode()
  }
}
var allPeople=people1.Union(people2,newpersoncomparer());
公共类人员比较:IEqualityComparer
{
公共布尔等于(人x,人y)
{
//ommited空检查等
返回x.Id==y.Id;
}
public int GetHashCode(Person obj)
{
//ommited空检查等
obj.Id.GetHashCode()
}
}
使用以下方法:

people1.AddRange(people2.Except(people1));
但首先需要在Person类中重写Equal和GetHashCode:

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }

    public override bool Equals(object obj)
    {
        if (!(obj is Person))
            return false;
        Person p = (Person)obj;
        return (p.Id == Id && p.Name == Name);
    }
    public override int GetHashCode()
    {
        return String.Format("{0}|{1}", Id, Name).GetHashCode();
    }
}
或者,您可以使用自定义相等比较器,然后使用
Distinct(new distinctiontemcomparer())

如果只需要根据
Id
进行区分,则可以从这两种方法中排除
名称


基于,第二种方法似乎更好,因为Microsoft已经建议不要在引用类型上重载运算符equals。

我认为最好的解决方案是使用LINQ。编写的代码非常简单和简短:

people1.AddRange(people2.Where(x => !people1.Any(y => x.Id == y.Id)));

你有没有想过改用
字典

您可以将
Id
用作
,并且它不允许存在重复的键

以下代码是我以前使用过的一种方式:

var dictionary = people1.ToDictionary(x => x.Id, x => x);

foreach(var person in people2)
{
    if(!dictionary.ContainsKey(item.Id))
    {
        dictionary.Add(item.Id, item);
    }
}
也许有更好的方法,但这对我来说很有效

这样,当您向字典中添加项目时,它将不允许您添加具有相同
Id
的内容


也检查<代码> HasStuts,因为它们做了类似的事情。

所以,你认为两个实例的人是基于ID的相同的吗?如果<代码>名称< /代码>属性不同,应该发生什么?应该保存在Pube中的那个还是应该被另一个替换?事实上,这是不可能的,因为我是ReTeRe。我从数据库中获取了这些数据。但如果你将此可能性作为一个答案,也许你可以帮助其他人。因为它不能解决你的问题,我希望有人(最好是公认的答案)将其包含在他们的问题中。我怀疑OP是否从我对问题的评论中考虑了这种情况。(如果两个
具有相同的
Id
但不同的
姓名
?)+1对于添加2个解决方案,不确定第二个是否有效,但它很容易阅读和测试。@Glenvanacker:如果
人1
很大,第二个应该比第一个好得多。@Fildor:我假设OP问了他们想问的问题。@JonSkeet公平,这只是一个想法。但这似乎很重要无论如何都是可能的。所以不用担心。更好的方法是使用dictionary[item.ID]=item。除非它更喜欢来自内部集合的数据,以防重复。这不会起作用。Union直接使用哈希代码进行比较。因此,仅实现Equals不会起作用。您需要添加一个适当的
GetHashCode(Person obj)
实现该功能。@RobinB correct-为了简洁起见,我从上面推荐了空检查、GetHashCode等。为了清晰起见,将进行更新。谢谢。我认为这可能是一个很大的陷阱,让人们稍后看到这一点,只需返回obj.GetHashCode()
,然后问自己为什么他们的
等于()
永远不会执行。
people1.AddRange(people2.Where(x => !people1.Any(y => x.Id == y.Id)));
var dictionary = people1.ToDictionary(x => x.Id, x => x);

foreach(var person in people2)
{
    if(!dictionary.ContainsKey(item.Id))
    {
        dictionary.Add(item.Id, item);
    }
}