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

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

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

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

Q&A

解決済

wrapした変数を格納するHashSetをつくりたい

kdt.nmk
kdt.nmk

総合スコア20

C#

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

4回答

1グッド

1クリップ

360閲覧

投稿2022/11/16 14:27

前提

タイトルの通りですが、C#でwrapした変数を重複無しで格納するコレクションを作りたいです。

当然ですが、既存のHashSetにオブジェクトを入れると、valueが同じでも、異なるオブジェクトであれば格納されてしまいます。

そこで、「コレクションにaddするときに、既に格納されているオブジェクトのvalueを参照して、重複するようであれば追加しない」というコレクションを作りたいです。

速度は必要ないので、二分木などのデータ構造は必要なく、単にforeachで全て確認するだけでいいので、Listを継承するなどの方法が分かれば解決しそうなのですが、そのようなことはできるのでしょうか。

どうぞよろしくお願いいたします。

実現したいこと

wrapした変数をvalueを基準として格納する、HashSetのようなコレクションを作りたい。

該当のソースコード

c#

1public class IDList 2{ 3 // MyHashSet<ID> list; の様にしたい 4 List<ID> list; 5 public IDList() 6 { 7 list = new List<ID>(); 8 } 9 public bool Add(ID id) 10 { 11 // このforeachをList内部で処理したい 12 foreach (var item in list) 13 { 14 if (item.value == id.value) 15 { 16 return false; 17 } 18 } 19 list.Add(id); 20 return true; 21 } 22} 23public class ID 24{ 25 public int value { get; } 26 public ID(int v) 27 { 28 value = v; 29 } 30}
TN8001👍を押しています

以下のような質問にはグッドを送りましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

グッドが多くついた質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

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

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

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

下記のような質問は推奨されていません。

  • 間違っている
  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

SurferOnWww

2022/11/16 21:56

「該当のソースコード」では何が期待と違うのか具体的に書いてください。

回答4

3

ベストアンサー

当然ですが、既存のHashSetにオブジェクトを入れると、valueが同じでも、異なるオブジェクトであれば格納されてしまいます。

はい。しかしそれの手当ても当然用意されています。

IDクラスをいじれる場合

IEquatable<T>を実装してください。

IEquatable<T> インターフェイス (System) | Microsoft Learn
クラスまたは構造体の値の等価性を定義する方法 - C# プログラミング ガイド | Microsoft Learn

C#9 以降ならrecordを使うのが手っ取り早いです。
レコード - C# リファレンス | Microsoft Learn

IDクラスをいじれない場合

HashSet<T>IEqualityComparer<T>を与えます。

HashSet<T> コンストラクター (System.Collections.Generic) | Microsoft Learn
IEqualityComparer<T> インターフェイス (System.Collections.Generic) | Microsoft Learn
EqualityComparer<T> クラス (System.Collections.Generic) | Microsoft Learn

.NET6です^^

cs

1using System.Diagnostics.CodeAnalysis; 2 3var idRecords = new HashSet<IdRecord>(); 4Console.WriteLine(idRecords.Add(new IdRecord(1))); // True 5Console.WriteLine(idRecords.Add(new IdRecord(2))); // True 6Console.WriteLine(idRecords.Add(new IdRecord(1))); // False 7Console.WriteLine(string.Join(", ", idRecords)); // IdRecord { Value = 1 }, IdRecord { Value = 2 } 8Console.WriteLine(new IdRecord(1) == new IdRecord(1)); // True 9 10Console.WriteLine(); 11 12 13var ids = new HashSet<ID>(new IDEqualityComparer()); 14Console.WriteLine(ids.Add(new ID(1))); // True 15Console.WriteLine(ids.Add(new ID(2))); // True 16Console.WriteLine(ids.Add(new ID(1))); // False 17Console.WriteLine(string.Join(", ", ids.Select(x => x.Value))); // 1, 2 18Console.WriteLine(new ID(1) == new ID(1)); // False 19 20 21 22record IdRecord(int Value); 23 24class ID 25{ 26 public int Value { get; } 27 public ID(int v) => Value = v; 28} 29 30class IDEqualityComparer : EqualityComparer<ID> 31{ 32 public override bool Equals(ID? x, ID? y) => x?.Value == y?.Value; 33 public override int GetHashCode([DisallowNull] ID obj) => obj.Value.GetHashCode(); 34}

投稿2022/11/16 22:02

TN8001

総合スコア8066

KOZ6.0, kdt.nmk, Zuishin👍を押しています

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

回答へのコメント

kdt.nmk

2022/11/17 11:20

ご返信ありがとうございます! IDクラスのEqualsをオーバーライドする方法をとって、完結なコードにすることができました! 複数の対応策を示していただき、コードまで書いてくださったおかげで、とても勉強になりました。

1

TN8001 さんの回答とダブるところがありますが・・・

HashSet<T> コンストラクターに以下の通り IEqualityComparer<T> を引数に取るオーバーロードがあります。

https://learn.microsoft.com/ja-jp/dotnet/api/system.collections.generic.hashset-1.-ctor?view=netframework-4.8#system-collections-generic-hashset-1-ctor(system-collections-generic-iequalitycomparer((-0)))

それを使って以下のようにしてはいかがですか? TN8001 さんの回答と違うところは .NET Framework 4.8 ベースであることと、EqualityComparer<T> 継承した比較用クラスの実装だけです。

EqualityComparer<T> を使う理由は以下の記事の Remarks を見てください。

EqualityComparer<T> Class
https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.equalitycomparer-1?view=netframework-4.8

C#

1using System; 2using System.Collections.Generic; 3 4namespace ConsoleAppHashSet 5{ 6 internal class Program 7 { 8 static void Main(string[] args) 9 { 10 var hashSet = new HashSet<ID>(new IdComparer()); 11 12 var id1 = new ID(1); 13 var id2 = new ID(1); 14 15 bool result = hashSet.Add(id1); 16 Console.WriteLine(result); 17 18 result = hashSet.Add(id1); 19 Console.WriteLine(result); 20 21 result = hashSet.Add(id2); 22 Console.WriteLine(result); 23 } 24 } 25 26 public class ID 27 { 28 public ID(int value) 29 { 30 this.Value = value; 31 } 32 33 public int Value { get; set; } 34 } 35 36 // Derive from this class to provide a custom implementation of the 37 // IEqualityComparer<T> generic interface for use with collection 38 // classes such as the Dictionary<TKey,TValue> generic class, or 39 // with methods such as List<T>.Sort. 40 class IdComparer : EqualityComparer<ID> 41 { 42 public override bool Equals(ID x, ID y) 43 { 44 if (Object.ReferenceEquals(x, y)) return true; 45 46 if (x is null || y is null) return false; 47 48 return x.Value == y.Value; 49 } 50 51 // Equals() が true を返した場合 GetHashCode() は比較した 52 // 両オブジェクトで同じ値を返さなければならない 53 public override int GetHashCode(ID id) 54 { 55 return id.Value.GetHashCode(); 56 } 57 } 58}

結果は:

イメージ説明

上記は .NET Framework 4.8 の例です。.NET 6.0 でも同じですが、デフォルトで null 許容参照型が有効になっていますので、その対応は必要です。

投稿2022/11/17 03:02

編集2022/11/17 03:20
SurferOnWww

総合スコア17435

kdt.nmk👍を押しています

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

回答へのコメント

kdt.nmk

2022/11/17 11:24

ご返信ありがとうございます。 今回は、IDクラスのEqualsをオーバーライドする方法を取ることにしました。 質問の仕方に対するご指摘もありがとうございます。 キーワードを知ることができればなんとかできそうだったため、シンプルな質問にしてしまいましたが、今後はわかりやすい質問を心がけたいと思います。

0

Text

1ある劣悪なハッシュ関数は同じ入力に対して異なるハッシュ値を返すことがある。 2インターネットの誤情報に騙されないように注意せよ。

投稿2022/11/16 16:46

atcoderyellow

総合スコア481

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

2022/11/17 02:03

こちらの回答が複数のユーザーから「質問に対する回答となっていない投稿」という指摘を受けました。

2022/11/16 19:04

こちらの回答が他のユーザーから「スパムと見受けられる内容を含む回答」という指摘を受けました。

2022/11/16 21:49

こちらの回答が他のユーザーから「攻撃的な表現などを含む不快な回答」という指摘を受けました。

0

Dictionary<int,ID>とかつかえばいいと思うけど、、、
IDのEqualsとGetHashCodeをオーバーライドしてHashSet<ID>使う手もあるけど、好みが分かれるところ。

投稿2022/11/16 15:29

matukeso

総合スコア1427

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

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

ただいまの回答率
86.02%

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

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

質問する

関連した質問

同じタグがついた質問を見る

C#

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