3

我有两个列表:

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)。

不知道我错过了什么。

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

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;

}
4

5 回答 5

6

来自 MSDN,对于 Union :

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

关联

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

这是实现此类的一个简单示例。

于 2013-10-04T14:39:47.520 回答
3

我不喜欢重写 Files 类 equals object 和 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();
    }
}
于 2013-10-04T15:07:55.493 回答
1

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

于 2013-10-04T14:36:51.300 回答
1

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

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());
于 2013-10-04T14:49:57.323 回答
0

来自MSDN Enumerable.Union 方法

如果要比较自定义数据类型的对象序列,则必须在类中实现 IEqualityComparer<T> 泛型接口。

特定于您的类的示例实现,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;
    }
}
于 2013-10-04T15:04:33.580 回答