質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

LINQ

LINQとはLanguage INtegrated Queryの略で、「統合言語クエリ」という意味です。C#やVisual Basicといった言語のコード内に記述することができるクエリです。

Q&A

解決済

1回答

3335閲覧

Enumerable.Distinct<T> 拡張メソッドでカスタムクラスを除外できない理由がわからない

twyujiro15

総合スコア217

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

LINQ

LINQとはLanguage INtegrated Queryの略で、「統合言語クエリ」という意味です。C#やVisual Basicといった言語のコード内に記述することができるクエリです。

1グッド

0クリップ

投稿2016/12/08 00:08

###疑問
カスタムクラスのシーケンスに対する Enumerable.Distinct<T> 拡張メソッドの挙動について、
既定の等値比較子による比較で "重複" とみなされない理由がわかりません。

###調査内容
下記公式サイトからの引用です。
MSDN:Enumerable.Distinct<TSource> メソッド (IEnumerable<TSource>)

既定の等値比較演算子 Default は、IEqualityComparer<T> ジェネリック インターフェイスを実装している型の値を比較するために使用されます。 カスタム データ型を比較するには、このインターフェイスを実装し、その型の GetHashCode メソッドと Equals メソッドを独自に用意する必要があります。

つまり IEqualityComparer<T> を実装しろ、ということです。
こう書いてあるのだからそうすべきだ、といってしまえばそれまでなのですが、
Distinct<T> の内部実装を覗くと次のようなコードが見つかります。

C#

1if (this.slots[i].hashCode == num && this.comparer.Equals(this.slots[i].value, value)) 2{ 3 return true; 4}

つまりハッシュコードが一致していることと、
既定の Comparer による等値比較が一致していることで
"重複" とみなしているということです。

###試してみたコード
というわけで以下のようなコードを試してみました。
単純な人物情報を表す Person クラスを作成し、
インスタンスが重複する要素を持つリストに対して Distinct<T> を使用しています。

途中、ハッシュコードによる比較や既定の等値比較演算子による比較をおこなっていますが、
どれも "一致" という結果となります。
これにも関わらず Distinct<T> 拡張メソッドによって "重複" とみなされない理由はなんでしょうか。

C#

1namespace LinqTest 2{ 3 using System; 4 using System.Collections.Generic; 5 using System.Linq; 6 7 class Program 8 { 9 static void Main(string[] args) 10 { 11 var p1 = new Person() { Name = "田中 淳平", Date = new DateTime(2011, 5, 2) }; 12 var p2 = new Person() { Name = "鈴木 ほのか", Date = new DateTime(2014, 3, 24) }; 13 var p3 = new Person() { Name = "小池 哲司", Date = new DateTime(2002, 6, 13) }; 14 var people = new List<Person>() { p1, p2, p1, p3 }; 15 var comparer = EqualityComparer<Person>.Default; 16 17 if (people[0].GetHashCode() == people[2].GetHashCode()) Console.WriteLine("GetHashCode は一致。"); 18 if (comparer.Equals(people[0], people[2])) Console.WriteLine("既定の Comparer による等値比較は一致。"); 19 if (comparer.GetHashCode(people[0]) == comparer.GetHashCode(people[2])) Console.WriteLine("既定の Comparer による GetHashCode は一致。"); 20 21 foreach (var p in people) 22 { 23 Console.WriteLine(p.Name + " (" + p.GetHashCode() + ")"); 24 } 25 26 Console.WriteLine("重複要素を除外します。"); 27 var newPeople = people.Distinct(); 28 foreach (var p in people) 29 { 30 Console.WriteLine(p.Name + " (" + p.GetHashCode() + ")"); 31 } 32 33 Console.ReadKey(); 34 } 35 } 36}

C#

1namespace LinqTest 2{ 3 using System; 4 5 /// <summary> 6 /// 人物データを表します。 7 /// </summary> 8 public class Person 9 { 10 /// <summary> 11 /// 氏名を取得または設定します。 12 /// </summary> 13 public string Name { get; set; } 14 15 /// <summary> 16 /// 更新日付を取得または設定します。 17 /// </summary> 18 public DateTime Date { get; set; } 19 } 20} 21
ozwk👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

こんにちは。
質問のコードでちゃんと除外されますよ?

問題はここにあります。

csharp

1var newPeople = people.Distinct(); 2foreach (var p in people) // ! 3{ 4 Console.WriteLine(p.Name + " (" + p.GetHashCode() + ")"); 5}

peopleをDistinctしたものをnewPeopleに格納しているのに、Distinctする前のpeopleを列挙しているからです。

Distinctの挙動は、質問者さんの理解で完璧に正しいです。

投稿2016/12/08 00:17

tamoto

総合スコア4103

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

twyujiro15

2016/12/08 00:22

あわわわわ…。 穴があったら入りたいです!! なんとアホなことを!恥ずかしい! ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問