我希望使用C#中的LINQ从列表中检索唯一项。 我有一个班级甲板,有一个属性卡,这是卡的列表。此外,班级卡还有套房式套房。我想要检索卡片列表中的所有套件项目,但只能查看独特的套件。我试过的代码是:
List<Suite> GetSuiteByCards(List<Card> cards)
{
List<Suite> list = cards.Select(c => c.Suite).Distinct().ToList();
return list;
}
如果我没弄错的话,这应该从卡片列表中检索所有独特的套房。但是,以下测试失败
// 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);
以上代码创建了一副小卡片(2张卡片),具有相同的套件。因此,以下代码应该评估为true:
d.Suites.Count == 1
除了我得到:
d.Suites.Count == 2
我已经省略了一些代码,但我认为它不相关。如果我用完整的牌组(即52张牌)运行代码,我会得到4个独特的套房,如预期的那样;因此我感到非常困惑。
我已经通过扩展方法解决了这个问题,但我想知道是否有一种简单的方法可以通过LINQ来实现。
答案 0 :(得分:3)
班级卡有套房式套房
心灵调试开启。我猜测Suite
是引用类型,并且您没有覆盖Object.Equals
和Object.GetHashCode
。
您需要覆盖Object.Equals
的{{1}}和Object.GetHashCode
。如果您未提供Suite
的实施,则Distinct
会使用EqualityComparer<Suite>.Default
。 IEqualityComparer<Suite>
返回的实施使用EqualityComparer<Suite>.Default
和Object.Equals
。因此,如果您不重写这些,那么实现返回模型引用相等(和引用的哈希代码)。
或者,实现Object.GetHashCode
以不通过引用相等性进行比较,并将实例传递给Enumerable.Distinct<TSource>(this IEnumerable<TSource>, IEqualityComparer<TSource>)
。
我已经省略了一些代码,但我认为它不相关。如果我用完整的牌组(即52张牌)运行代码,我会得到4个独特的套房,如预期的那样;因此我感到非常困惑。
这有点相关,但让我猜一下发生了什么。在上面的代码中,完整列表可能更像是:
IEqualityComparer<Suite>
所以在这里你要创建两个代表黑桃的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};
个实例。但是,这两个实例不会相等,因为它们是不同的实例,并且您没有覆盖Suite
(和Equals
必要)。
然而,就52张牌的情况而言,我打赌你做了这样的事情:
GetHashCode
然后
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.
};
现在代表空格的所有卡片都与var deck = from suite in suites
from value in values
select new Card(suite, value);
共享相同的引用,因此Suite
也可以。
顺便说一句,我不会将套装和值建模为参考类型。它们确实是价值类型。心是一颗心,这就是它的身份。它的身份不是由谁来定义,而是由它是什么来定义。
这样就可以避免整个问题的开始,因为值类型的默认相等运算符是值相等。