获取一个唯一列表<;T>;从三个非唯一列表<;T>';s

本文关键字:列表 gt 唯一 lt 三个 一个 获取 | 更新日期: 2023-09-27 18:21:29

我有三个User:列表

ICollection<User> listOne = _somewhere.GetUsers(1);
ICollection<User> listTwo = _somewhere.GetUsers(2);
ICollection<User> listThree = _somewhere.GetUsers(3);

要进行比较的"唯一"标识符是一个名为"电子邮件"的字符串字段。

我如何从这三个列表中得到一个唯一的列表(例如,没有重复)。

在使用Except之前,我从两个列表中获得了一个唯一的列表,但不确定如何使用三个列表?我必须对前两个使用Except,然后对前两和第三个的结果再次使用吗?

另外,我应该提到用户的列表来自外部Web API调用,并且不能保证每个列表都有一个唯一的电子邮件地址列表。

所以我需要两个步骤:

  1. 在每个列表中,消除重复
  2. 将这三个唯一列表组合起来,得到一个唯一列表

获取一个唯一列表<;T>;从三个非唯一列表<;T>';s

您只需联合列表,并在组合列表上执行一次重复数据消除(使用Distinct())。

var uniqueList = listOne.Union(listTwo)
                        .Union(listThree)
                        .Distinct(new EmailComparer())
                        .ToList();

因为比较器可以像这样简单:

class EmailComparer : IEqualityComparer<User>
{
    public bool Equals(User x, User y)
    {
        return x.Email == y.Email;
    }
    public int GetHashCode(User obj)
    {
        return obj.Email.GetHashCode();
    }
}

编辑:

正如评论中所指出的,如果我们将自定义电子邮件比较器应用于Union():,则不需要Distinct()

var emailComparer = new EmailComparer();
var uniqueList = listOne.Union(listTwo, emailComparer)
                        .Union(listThree, emailComparer)
                        .ToList();

如果从具有相同电子邮件的用户列表中选择哪个用户并不重要,则可以执行以下操作:

var res = listOne.Concat(listTwo).Concat(listThree)
    .GroupBy(u => u.Email)
    .Select(g => g.First());

同样,这假设当电子邮件地址相同时,选择哪个用户并不重要。

首先定义我们想要如何定义唯一性:

private class EmailEqComparer : IEqualityComparer<User>
{
  public bool Equals(User x, User y)
  {
    //don't bother shortcutting on reference equality, since if they come from
    //separate web-calls it's unlikely to happen, though it could
    //with some optimisations on the web-client code.
    if(x == null)
      return y == null;
    if(y == null)
      return false;
    return x.Email == y.Email;
  }
  public int GetHashCode(User obj)
  {
    return obj == null ? 0 : obj.Email.GetHashCode();
  }
}

现在对每个项目调用Distinct,并将结果放入一个列表中:

var distinctUnion = listOne.Concat(listTwo).Concat(listThree).Distinct(new EmailEqComparer());