2011-07-28 157 views
3

有一个非常相关的问题:Create List<CustomObject> from List<string>但它并不涉及在同一时间删除重复项。从列表<OtherObject>创建列表<CustomObject>,删除重复项。

我有以下的类的实例:

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(); 

的问题是,有在结果列表中重复。我究竟做错了什么?

+0

5个答案在60秒内:) – Gluip

+0

这就是我们喜欢的原因吧? :) – JYelton

+0

@Gluip:是不是一个昵称笼电影? –

回答

5

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

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

要么定义一个自定义IEqualityComparer<Owner>(因为您要在所有者序列中调用截然不同),要么为您的课程添加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; 
    } 
} 

一旦你这样做,你写的查询将工作得很好。

+0

我看到我们以类似的方式思考!实际上是+1 *显示*如何实现这些方法。 – dlev

+0

对“正确”答案的强硬调用 - @dlev显示了一种使用LINQ的解决方法,这非常棒,因为这是一次性填充树视图(我选择这种情况)。然而,詹姆斯提供了一个非常好的例子,说明如何做到这一点“防弹”,如果我在这门课上做了更多的事情,它将会适用。 – JYelton

+0

@dlev:的确如此!我们摇滚!!!!呃...东西... –

1

您所有者对象必须实现IComparable<>才能使Distinct正常工作。你将不得不决定什么使得Owner与另一个Owner相同。

5

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

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

或者,你可以只实现EqualsGetHashCodeOwner,和你原来的方法是可行的。

+0

这意味着要记住在每个只需要不同值的查询中执行此操作。实现IComparable更简单 – jaywayco

+0

@jay我认为'Equals()'和'GetHashCode()'应该这样做,因为内部'Distinct'只是试图通过其哈希码将下一个元素添加到集合中,并且如果它已经那里。这就是说,“IComparable”也是一个不错的选择。 – dlev

+0

@dlev:哈,哇,我们一起在这里滚! –

0

我想这一独特的尝试获取来自Owner类,你实例化的唯一对象,为什么不选择串

试试这个:

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

然后从他们

1

创建一个列表不同的用途等同于确定两个元素是否相同。你可以为你的主人实现平等。或者先选择这样的名字:

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

您的假设名称是所有者对象的唯一标识符 – jaywayco

+0

部分要求是唯一所有者名称的权利? – Gluip