简体   繁体   English

使用LINQ C#按属性分配的唯一对象

[英]Unique objects by Property using LINQ C#

I wish to retrieve the unique items from a list using LINQ in C#. 我希望在C#中使用LINQ从列表中检索唯一项。 I have a class Deck, with a property Cards which is a list of Card. 我有一个Deck课,带有一个Cards属性,它是Card的列表。 Furthermore, the class Card has a property Suite of type Suite. 此外,类别Card具有套件类型的属性套件。 I want to retreive all the Suite items in the List of Card, but only the unique suites. 我想检索卡片列表中的所有套件项目,但只检索唯一的套件。 The code I have tried is: 我试过的代码是:

List<Suite> GetSuiteByCards(List<Card> cards)
    {
        List<Suite> list = cards.Select(c => c.Suite).Distinct().ToList();
        return list;
    }

If I am not mistaken, this should retrieve all the unique suites from the list of cards. 如果我没记错的话,这应该从卡列表中检索所有唯一的套件。 However, the following test fails 但是,以下测试失败

// Creating test cards
Card a = new Card(suite="spade", value="ace");
Card b = new Card(suite="spade", value="king");
List<Card> cards = new List<Card>(2) {a, b}; 

// Creating deck of cards
Deck d = new Deck(cards);

The above code creates a small deck of cards (2 cards), with the same suite. 上面的代码使用相同的套件创建了一小叠纸牌(两张纸牌)。 So, the following code should evaluate true: 因此,以下代码应评估为true:

d.Suites.Count == 1

except that I am getting: 除了我得到:

d.Suites.Count == 2

I have ommitted some code, but I don't think it is relevant. 我省略了一些代码,但是我认为这无关紧要。 If I run the code with a full deck (ie 52 cards) I get 4 unique Suites, as expected; 如果我使用一副完整的代码(即52张卡片)运行代码,则可以得到4个独特的套件,这与预期的一样; thus I am quite baffled. 因此我很困惑。

I have resolved the issue through an extension method, but I was wondering if there was a simple way to do it via LINQ. 我已经通过扩展方法解决了这个问题,但是我想知道是否有一种简单的方法可以通过LINQ来解决。

the class Card has a property Suite of type Suite 类别卡具有套房类型的套房

Psychic debugging powers on. 通灵的调试电源。 I am guessing that Suite is a reference type, and you didn't override Object.Equals and Object.GetHashCode . 我猜Suite是一种引用类型,并且您没有重写Object.EqualsObject.GetHashCode

You need to override Object.Equals and Object.GetHashCode for Suite . 您需要重写Suite Object.EqualsObject.GetHashCode Distinct uses EqualityComparer<Suite>.Default if you don't provide an implementation of IEqualityComparer<Suite> . Distinct使用EqualityComparer<Suite>.Default如果不提供IEqualityComparer<Suite>的实现,则使用IEqualityComparer<Suite> The implementation returned by EqualityComparer<Suite>.Default uses Object.Equals and Object.GetHashCode . EqualityComparer<Suite>.Default返回的实现使用Object.EqualsObject.GetHashCode So, if you don't override these, then the implementation returned models reference equality (and hash code by reference). 因此,如果您不重写它们,则实现返回的模型将引用相等(并按引用散列代码)。

Alternatively, implement IEqualityComparer<Suite> to compare not by reference equality and pass an instance to Enumerable.Distinct<TSource>(this IEnumerable<TSource>, IEqualityComparer<TSource>) . 或者,实现IEqualityComparer<Suite>以不通过引用相等进行比较,然后将实例传递给Enumerable.Distinct<TSource>(this IEnumerable<TSource>, IEqualityComparer<TSource>)

I have ommitted some code, but I don't think it is relevant. 我省略了一些代码,但是我认为这无关紧要。 If I run the code with a full deck (ie 52 cards) I get 4 unique Suites, as expected; 如果我使用一副完整的代码(即52张卡片)运行代码,则可以得到4个独特的套件,这与预期的一样; thus I am quite baffled. 因此我很困惑。

It's kind of relevant, but let me take a guess as to what is going on. 这有点相关,但是让我猜测发生了什么。 In your above code, the full listing is probably something more like: 在上面的代码中,完整的清单可能更像是:

Card a = new Card(new Suite("spade"), new Value("ace"));
Card b = new Card(new Suite("spade"), new Value("king"));
List<Card> cards = new List<Card>(2) {a, b}; 

and so here you are creating two instances of Suite representing spades. 所以在这里您要创建两个代表锹的Suite实例。 However, these two instances will not compare as equal because they are different instances and you haven't overridden Equals (and GetHashCode by necessity). 但是,这两个实例不会比较相等,因为它们是不同的实例,并且您没有覆盖Equals (和GetHashCode必不可少)。

However, in the case of the 52-card deck, I bet you did something like this: 但是,对于52张卡组,我敢打赌,您做了这样的事情:

List<Suite> suites = new List<Suite>() suites {
    new Suite("spade"),
    new Suite("heart"),
    new Suite("club"),
    new Suite("diamond")
};

List<Value> values = new List<Value>() values {
    new Value("ace"),
    new Value("king"),
    // etc.
};

and then 接着

var deck = from suite in suites
           from value in values
           select new Card(suite, value);

and now all the cards the represent a space are sharing the same reference to Suite and thus Distinct is okay. 现在,代表空间的所有卡都共享对Suite的相同引用,因此Distinct可以。

By the way, I wouldn't model suits and values as reference types anyway. 顺便说一句,我还是不会将西装和值建模为参考类型。 They really are value types. 它们确实是价值类型。 A heart is a heart, and that is its identity. 心脏就是心脏,那就是它的身份。 It's identity is not defined by who it is, but rather by what it is. 它的身份不是由它是谁来定义,而是由它是什么来定义。

This would obviate the whole problem to begin with anyway, since the default equality operator for value types is value equality. 无论如何,这将消除整个问题,因为值类型的默认相等运算符为值相等。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM