从List <otherobject>创建列表<customobject>,删除重复项。</otherobject> </customobject>

时间:2011-07-28 20:19:32

标签: c# linq

有一个非常相关的问题:Create List<CustomObject> from List<string>但它并不涉及同时删除重复项。

我有以下课程示例:

class Widget
{
    public string OwnerName;
    public int SomeValue;
}

class Owner
{
    public string Name;
    public string OtherData;
}

我想根据小工具列表创建所有者列表,但只能创建唯一的所有者名称。

以下是我的尝试:

List<Owner> Owners = MyWidgetList.Select(w => new Owner { Name = w.OwnerName }).Distinct().ToList();

问题是结果列表中有重复。我做错了什么?

5 个答案:

答案 0 :(得分:5)

您需要为对象定义GetHashCode()Equals(),以定义自定义类型的相等性。否则,它会根据引用本身进行比较。

这是因为LINQ扩展方法使用IEqualityComparer接口来比较对象。如果您没有定义自定义比较器(您可以通过创建一个实现IEqualityComparer<Owner>的单独类来完成),它将使用默认的相等比较器,它使用类Equals()GetHashCode()定义。如果您不覆盖它们,则会在Equals()上引用比较并返回默认对象哈希码。

定义自定义IEqualityComparer<Owner>(因为您在所有者序列上调用distinct)或为您的班级添加Equals()GetHashCode()

public class Owner
{
    public string Name;
    public string OtherData;

    public override Equals(object other)
    {
        if (ReferenceEquals(this, other))
            return true;

        if (other == null)
            return false;

        // whatever your definition of equality is...
        return Name == other.Name && OtherData == other.OtherData;
    }

    public override int GetHashCode()
    {
        int hashCode = 0;

        unchecked
        {
           // whatever hash code computation you want, but for example...
            hashCode += 13 * Name != null ? Name.GetHashCode() : 0;
            hashCode += 13 * OtherData != null ? OtherData.GetHashCode() : 0;
        }

        return hashCode;
    }
}

一旦你这样做,你写的查询就可以了。

答案 1 :(得分:5)

Owner的默认比较器无法正常工作(因为它只是使用引用相等),因此Distinct认为所有对象都不同。一种解决方案是使用两个Select s:

var owners = MyWidgetList.Select(w => w.OwnerName).Distinct().Select(w => new Owner { Name = w }).ToList();

或者,您可以在Equals上实施GetHashCodeOwner,原始方法也可以。

答案 2 :(得分:1)

您的所有者对象必须为IComparable<>实施Distinct才能正常运行。您必须决定使Owner与另一个Owner相同的原因。

答案 3 :(得分:1)

Distinct使用equals来确定两个元素是否相同。您可以为您的所有者实施equals。或者首先选择名称:

List<Owner> Owners = MyWidgetList.Select(w => w.OwnerName).Distinct()
 .Select(s=>new Owner{Name = s}.ToList();

答案 4 :(得分:0)

我想这个Distinct试图从你实例化的Owner类中获取唯一对象,为什么不选择字符串

试试这个:

List<string> OwnersStr = MyWidgetList.Select(w =>  w.OwnerName).Distinct().ToList();

然后从他们创建一个列表