在 c 中使用 linq intersect 和 equality 将多个列表合并为一个不同的列表#

Combining several lists into a single distinct list using linq intersect and equality in c#

提问人:Blake Rivell 提问时间:1/10/2023 最后编辑:M. JustinBlake Rivell 更新时间:11/3/2023 访问量:82

问:

我需要使用 linq 和 intersect 将多个列表合并为一个 combinedDistinct 列表。我最终得到一个空列表。知道我可能做错了什么吗?

这是我的代码:

合并所有不同的材料项目

List<Material> combinedMaterialList = new List<Material>();

foreach (var project in projects)
{
     combinedMaterialList = combinedMaterialList.Intersect(project.Materials).ToList();
}

这是 Material 类,因为 intersect 将基于 Equality 工作:

public int Id { get; set; }
public int ExternalId { get; set; }
public string? Name { get; set; }
public decimal Quantity { get; set; }

public bool Equals(Material m)
{
    if (m is null)
    {
        return false;
    }

    // Optimization for a common success case.
    if (Object.ReferenceEquals(this, m))
    {
        return true;
    }

    // If run-time types are not exactly the same, return false.
    if (this.GetType() != m.GetType())
    {
        return false;
    }

    // Return true if the fields match.
    // Note that the base class is not invoked because it is
    // System.Object, which defines Equals as reference equality.
    return (ExternalId == m.ExternalId);
}

    public override int GetHashCode()
    {
        return HashCode.Combine(Id, ExternalId, Name, Quantity);
    }
C# LINQ 相等

评论

1赞 Jeff Mercado 1/10/2023
你的类实现了吗?您还必须覆盖。MaterialIEquatable<Material>Equals(object)
0赞 Blake Rivell 1/10/2023
@JeffMercado 不,它没有。您能否为我指出一个位置,并举例说明如何完全实现平等。我有一种感觉,我错过了一些东西。对不起,我在 vscode 中,通常 visual studio IDE 会帮助我解决这个问题。
1赞 John Wu 1/10/2023
您的类不需要(也可能不应该)实现 .类将是一个单独的类,您可以将其作为参数传递给方法。IEqualityComparerIEqualityComparerIntersect
3赞 Jeff Mercado 1/10/2023
由于您要在要比较的类中实现比较,因此您需要使用 . 用于使用不同的实现来比较所需类型的对象。例如,IEquatable<T>IEqualityComparer<T>StringComparer
1赞 Andrew Williamson 1/10/2023
Union 删除重复元素

答:

1赞 Dmitry Bychenko 1/10/2023 #1

首先,请确保你已经实现了 和 对于类:EqualsGetHashCodeMaterial

public class Material: IEquatable<Material> {
  ...
  
  public bool Equals(Material other) {
    if (ReferenceEquals(this, other))
      return true;
    if (other is null)
      return false;

    return ExternalId == other.ExternalId;
  }

  public override bool Equals(object o) => o is Material other && Equals(other);

  // Note, that GetHashCode must not be more restrictive than Equals:
  // If Equals compare ExternalId only, so must do GetHashCode
  public override int GetHashCode() => ExternalId; 
}

实施后,您应该选择以下方法之一:Equals

  • Intersect两个列表中的所有项目
  • Union至少一个列表中的所有项目
  • Except:第一个列表中的所有项目,但不在第二个列表中

在任何情况下,重复项都将被删除。

例如:

// Since combinedMaterialList is empty,
// Intersect or Except have no meaning here: the result will be 
// an empty list. The only reasonable choice is Union 
List<Material> combinedMaterialList = new List<Material>();

// Combined list contains item from all project.Materials,
// duplicates removed
foreach (var project in projects) {
  combinedMaterialList = combinedMaterialList
    .Union(project.Materials)
    .ToList();
}