【问题标题】:Attempting to merge two Lists<> via Union. Still have duplicates试图通过联合合并两个列表<>。仍有重复
【发布时间】:2013-10-04 14:33:50
【问题描述】:

我有两个列表:

List<L1>, List<L2>

L1 = { detailId = 5, fileName = "string 1" }{ detailId = 5, fileName = "string 2" }
L2 = { detailId = 5, fileName = "string 2" }{ detailId = 5, fileName = "string 3" }

我想将它们结合起来,不要重复:

List<L3>

L1 = { detailId = 5, fileName = "string 1" }{ detailId = 5, fileName = "string 2" }{ detailId = 5, fileName = "string 3" }

我试过了:

L1.Union(L2).ToList();
L1.Concat(L2).Distinct().ToList();

但两者都返回重复项 (1, 2, 2, 3)。

不知道我错过了什么。

edit 方法如下。它采用一个列表并从一个分隔字符串创建另一个列表,并尝试将它们组合起来。

private List<Files> CombineList(int detailId, string fileNames)
{
    List<Files> f1 = new List<Files>();
    List<Files> f2 = new List<Files>();
    f1 = GetFiles(detailId, false);
    if (f1[0].fileNames != "")
    {
        string[] names = fileNames.Split('|');
        for (int i = 0; i < names.Length; i++)
        {
            Files x = new Files();
            x.detailId = detailId;
            x.fileNames = names[i];
            f2.Add(x);
        }
        List<Files> f3 = f1.Union(f2).ToList();
    }
    return f3;

}

【问题讨论】:

  • 对象是如何比较的? Union 使用默认的相等比较器
  • 我会用我正在使用的方法进行编辑。
  • 那是因为你还没有在L1L2上实现IEquatable&lt;T&gt;

标签: c# asp.net list


【解决方案1】:

来自 MSDN,对于 Union:

默认相等比较器 Default 用于比较 实现 IEqualityComparer(Of T) 泛型的类型 界面。要比较自定义数据类型,您需要实现此 接口并提供您自己的 GetHashCode 和 Equals 方法 输入。

link

由于您使用自定义类型,您需要覆盖GetHashCodeEquals 或提供一个实现IEqualityComparer 接口的对象(最好是IEquatable)并将其作为第二个参数提供给@987654327 @。

Here's a simple example of implementing such a class.

【讨论】:

  • 他不必实现IEqualityComparer&lt;T&gt;,只需覆盖GetHashCode() 和Equals(object) 就足够了。还实现IEquatable&lt;T&gt; 会更好。
  • 这看起来是我需要的。我会读一点并尝试实现它。
  • 您的最后一句话应该是:由于您使用自定义类型,您需要覆盖GetHashCodeEquals 方法,最好实现IEquatable&lt;T&gt;;或者提供一个实现IEqualityComparer&lt;T&gt;接口的对象,并将其作为第二个参数提供给Union。
【解决方案2】:

我不喜欢重写 Files 类 equals 对象和 getHashCode,因为您正在干扰对象。让另一个对象执行此操作,然后将其传入。这样,如果您以后遇到问题,只需将其换出并传递另一个 IEqualityComparer 这是一个您可以测试的示例

public void MainMethod()
{
    List<Files> f1 = new List<Files>() { new Files() { detailId = 5, fileName = "string 1" }, new Files() { detailId = 5, fileName = "string 2" } };
    List<Files> f2 = new List<Files>() { new Files() { detailId = 5, fileName = "string 2" }, new Files() { detailId = 5, fileName = "string 3" } };

    var f3 = f1.Union(f2, new FilesComparer()).ToList();
    foreach (var f in f3)
    {
    Console.WriteLine(f.detailId + " " + f.fileName);
    }

}

public class Files
{
    public int detailId;
    public string fileName;
}

public class FilesComparer : IEqualityComparer<Files>
{
    public bool Equals(Files x, Files y)
    {
        return x.fileName == y.fileName;
    }

    public int GetHashCode(Files obj)
    {
        return obj.fileName.GetHashCode();
    }
}

【讨论】:

  • 这与我使用 Solarbear 的建议提出的解决方案非常相似。
【解决方案3】:

如果您的元素没有实现某种比较接口(Object.Equals、IEquatable、IComparable 等),那么它们之间的任何相等性测试都将涉及ReferenceEquals,其中两个不同的对象是两个不同的对象,即使它们的所有成员都包含相同的值。

【讨论】:

  • IComparable 无济于事。并且 GetHashCode() 也需要被覆盖。
【解决方案4】:

如果要合并对象列表,则需要为相等比较定义一些标准。下面的例子说明了这一点:

class MyModelTheUniqueIDComparer : IEqualityComparer<MyModel>
{
    public bool Equals(MyModel x, MyModel y)
    {
        return x.SomeValue == y.SomeValue && x.OtherValue == y.OtherValue;
    }

    // If Equals() returns true for a pair of objects 
    // then GetHashCode() must return the same value for these objects.

    public int GetHashCode(MyModel myModel)
    {
        unchecked
        {
            int hash = 17;
            hash = hash * 31 + myModel.SomeValue.GetHashCode();
            hash = hash * 31 + myModel.OtherValue.GetHashCode();
            return hash;
        }
    }
}

然后你可以调用得到结果:

var result = q1.Union(q2, new MyModelTheUniqueIDComparer());

【讨论】:

  • 他不希望他们只比较 ID;他希望基于这两个属性来定义相等性,否则他的示例中只有一个结果。
  • 现在你的 equals 和 gethashcode 方法没有使用相同的相等定义,这真的很糟糕
  • @Servy:哈哈。刚看到那个。给我几个;)
【解决方案5】:

来自MSDN Enumerable.Union Method

如果您想比较自定义数据类型的对象序列,您可以 必须实现 IEqualityComparer 中的泛型接口 类。

一个特定于您的 Files 类的示例实现,以便在合并两个自定义类型的集合时 Union 可以正常工作:

public class Files : IEquatable<Files>
{
    public string fileName { get; set; }
    public int detailId { get; set; }

    public bool Equals(Files other)
    {

        //Check whether the compared object is null. 
        if (Object.ReferenceEquals(other, null)) return false;

        //Check whether the compared object references the same data. 
        if (Object.ReferenceEquals(this, other)) return true;

        //Check whether the products' properties are equal. 
        return detailId.Equals(other.detailId) && fileName.Equals(other.fileName);
    }

    // If Equals() returns true for a pair of objects  
    // then GetHashCode() must return the same value for these objects. 

    public override int GetHashCode()
    {

        //Get hash code for the fileName field if it is not null. 
        int hashFileName = fileName == null ? 0 : fileName.GetHashCode();

        //Get hash code for the detailId field. 
        int hashDetailId = detailId.GetHashCode();

        //Calculate the hash code for the Files object. 
        return hashFileName ^ hashDetailId;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-17
    • 2023-02-26
    • 1970-01-01
    • 2013-09-08
    • 1970-01-01
    • 2018-10-08
    • 1970-01-01
    相关资源
    最近更新 更多