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

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

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

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

Q&A

解決済

4回答

796閲覧

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

kdt.nmk

総合スコア20

C#

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

1グッド

0クリップ

投稿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👍を押しています

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

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

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

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

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

退会済みユーザー

退会済みユーザー

2022/11/16 21:56

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

回答4

0

ベストアンサー

当然ですが、既存の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

総合スコア9321

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

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

kdt.nmk

2022/11/17 11:20

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

0

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
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

kdt.nmk

2022/11/17 11:24

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

0

Text

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

投稿2022/11/16 16:46

atcoderyellow

総合スコア481

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

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

0

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

投稿2022/11/16 15:29

matukeso

総合スコア1590

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問