構造体をIndexOfする〜VB2008+Equalsいろいろ
- 2010.03.31 Wednesday
- 22:40
プログラムを作るとき、変数のまとまりを構造体として定義して作ることがある。
その構造体を配列にした場合、あの構造体のあの部分を検索したいなぁと思ったりする。
1つの変数ならIndexOfで簡単に位置が取得(検索)できるのですが、
構造体の場合、普通にIndexOfすると構造体同士の比較となってしまい、
構造体の中のあるデータに対しての比較というのはできません。
今回はその話題です。
結論から言うと、EqualsをOverrides(オーバーライズ)してあげればOKです!
ではサンプル(VB.net)
まず構造体(ここでは果物構造体)を作ります。
これで構造体の準備完了。
続いて、テスト
という感じで、Forループで回したりしなくてもIndexOfだけで検索が可能になります。
もちろん、IndexOfは先頭から検索をかけるので、
同じ文字がある場合は先に出てきた方のインデックス番号が返されます。
追記
構造体の比較の場合、次の方が良いようです。
ただし、この場合は、構造体同士の比較内でFuruitNameだけを対象にした検索をしたいという場合です。
つまり、上のIEquatable(Of Fruit)を書かないで普通に次を検索すると
「やまがた」と「やまがたけん」が異なるので、検索できません。
しかし、上でユーザー独自の検索(IEquatable(Of Fruit)を作る)に変えると、
「さくらんぼ」だけで比較するので、3が返ってきます。
もし、構造体同士は今まで通りで、文字列で判別したいという場合は、
上のなんでも良いObjectでの比較を行うことになる。
ところで、Fruit以外、例えば、IEquatable(Of String)と追加して、
文字列だけのFunction Equalsを作ってもその関数には入らないようなので、
Fruit構造体以外で検索したい場合は、Equals(ByVal obj As Object)を追加する必要があるようです。
※あくまでサンプルですので、細かなところはチューニングしてください。
上では
Dim FruitName As String
と宣言していますが、実際に構造体やクラスを作成する場合は、プロパティを利用してください。
追記
Equalsに絡んで、上の例以外での比較を考えたいことがある。
例えば、配列などで重複データを削除したい場合などである。
上の例ではFruitNameだけを比較しているため、Prefectureが異なっていても同じとしてしまう。
なので、Prefectureも比較したい場合別の比較が必要となる。
そういうときは、Implements IEqualityComparer(Of T)を使うと上とは別の比較が可能となる。
というクラスを作って
というデータを
aFruit.Distinct.ToArray したときと、
aFruit.Distinct(New FruitComparer).ToArray したときを比較すると、
Distinctだけでは、Prefectureに関係なくFruitNameで比較するため、
上の5つの配列だけが返されるが、FruitComparerで比較すると、ながの、とっとり、ふくおかの合計8つの配列が返される。
なお、obj.GetHashCode とすると、構造体のハッシュコードが返されるため、
a = bとしていれば同じハッシュコードが返ると思うが、
a = new Fruitとしてbと全く同じものを入れていても異なるハッシュコードが返ることがあるので、
obj.FruitName.GetHashCode(どれか基準となる値)とやっておいた方が良いようだ
参考URL
自作クラスのEqualsメソッドをオーバーライドして、等価の定義を変更する
C# Distinct IEnumerable カスタム メソッド <T> を
関連投稿
構造体をソートする〜VB2008
クラスや構造体はPublicにするかPropertyにするか〜VS2008
その構造体を配列にした場合、あの構造体のあの部分を検索したいなぁと思ったりする。
1つの変数ならIndexOfで簡単に位置が取得(検索)できるのですが、
構造体の場合、普通にIndexOfすると構造体同士の比較となってしまい、
構造体の中のあるデータに対しての比較というのはできません。
今回はその話題です。
結論から言うと、EqualsをOverrides(オーバーライズ)してあげればOKです!
ではサンプル(VB.net)
まず構造体(ここでは果物構造体)を作ります。
|
これで構造体の準備完了。
続いて、テスト
|
という感じで、Forループで回したりしなくてもIndexOfだけで検索が可能になります。
もちろん、IndexOfは先頭から検索をかけるので、
同じ文字がある場合は先に出てきた方のインデックス番号が返されます。
追記
構造体の比較の場合、次の方が良いようです。
|
ただし、この場合は、構造体同士の比較内でFuruitNameだけを対象にした検索をしたいという場合です。
つまり、上のIEquatable(Of Fruit)を書かないで普通に次を検索すると
|
「やまがた」と「やまがたけん」が異なるので、検索できません。
しかし、上でユーザー独自の検索(IEquatable(Of Fruit)を作る)に変えると、
|
「さくらんぼ」だけで比較するので、3が返ってきます。
もし、構造体同士は今まで通りで、文字列で判別したいという場合は、
上のなんでも良いObjectでの比較を行うことになる。
ところで、Fruit以外、例えば、IEquatable(Of String)と追加して、
文字列だけのFunction Equalsを作ってもその関数には入らないようなので、
Fruit構造体以外で検索したい場合は、Equals(ByVal obj As Object)を追加する必要があるようです。
※あくまでサンプルですので、細かなところはチューニングしてください。
上では
Dim FruitName As String
と宣言していますが、実際に構造体やクラスを作成する場合は、プロパティを利用してください。
追記
Equalsに絡んで、上の例以外での比較を考えたいことがある。
例えば、配列などで重複データを削除したい場合などである。
上の例ではFruitNameだけを比較しているため、Prefectureが異なっていても同じとしてしまう。
なので、Prefectureも比較したい場合別の比較が必要となる。
そういうときは、Implements IEqualityComparer(Of T)を使うと上とは別の比較が可能となる。
|
というクラスを作って
|
というデータを
aFruit.Distinct.ToArray したときと、
aFruit.Distinct(New FruitComparer).ToArray したときを比較すると、
Distinctだけでは、Prefectureに関係なくFruitNameで比較するため、
上の5つの配列だけが返されるが、FruitComparerで比較すると、ながの、とっとり、ふくおかの合計8つの配列が返される。
なお、obj.GetHashCode とすると、構造体のハッシュコードが返されるため、
a = bとしていれば同じハッシュコードが返ると思うが、
a = new Fruitとしてbと全く同じものを入れていても異なるハッシュコードが返ることがあるので、
obj.FruitName.GetHashCode(どれか基準となる値)とやっておいた方が良いようだ
参考URL
自作クラスのEqualsメソッドをオーバーライドして、等価の定義を変更する
C# Distinct IEnumerable カスタム メソッド <T> を
関連投稿
構造体をソートする〜VB2008
クラスや構造体はPublicにするかPropertyにするか〜VS2008