#はじめに
VB.netで自作クラスのインスタンスを格納したしリストを扱う際、任意のプロパティをキーにしてソートする方法を実装するのに手間取ったので、健忘禄として記事にしておきます。
#1.クラスの用意
例として名前、ID、年齢のプロパティを持つUserクラスを定義します。
Public Class User
Public ReadOnly Property Name As String
Public ReadOnly Property Id As String
Public ReadOnly Property Age As Integer
'コンストラクタ
Public Sub New(ByVal name As String, ByVal id As String, ByVal age As Integer)
Me.Name = name
Me.Id = id
Me.Age = age
End Sub
End Class
#2.インスタンスを生成しリストに格納
Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'インスタンス生成
Dim user1 As New User("Taro", "zx33", 30)
Dim user2 As New User("Dai", "bu12", 30)
Dim user3 As New User("Hanako", "as88", 25)
Dim user4 As New User("Yoko", "oy90", 25)
Dim user5 As New User("Kou", "ko32", 25)
Dim user6 As New User("Taro", "ko32", 30)
'User型のリスト作成
Dim users As New List(Of User)
'リストに6つのインスタンス追加
users.Add(user1)
users.Add(user2)
users.Add(user3)
users.Add(user4)
users.Add(user5)
users.Add(user6)
'リストに入っているユーザーの名前、ID、年齢を順番に表示
For Each user In users
Debug.Print(user.Name & " " & user.Id & " " & user.Age)
Next
End Sub
出力結果
Taro zx33 30
Dai bu12 30
Hanako as88 25
Yoko oy90 25
Kou ko32 25
Taro ko32 30
#3.比較用のメソッドを用意
''' <summary>
''' 年齢をキーにして並び順を比較する
''' </summary>
''' <param name="a"></param>
''' <param name="b"></param>
''' <returns>
''' 負の値 : インスタンス a は、並べ替え順序において b の前になります。
''' 0 : インスタンス a は、並べ替え順序で、b と同じ位置に出現します。
''' 正の値 : インスタンス a は、並べ替え順序において b の後になります。
''' </returns>
Private Function CompareByAge(ByVal a As User, ByVal b As User) As Integer
Return a.Age - b.Age
End Function
#4.比較メソッドを使ってソートする
sortメソッドの引数にAdressOf 比較メソッドを設定します。
'年齢の昇順でソート
users.Sort(AddressOf Me.CompareByAge)
'リストに入っているユーザーの名前、ID、年齢を順番に表示
For Each user In users
Debug.Print(user.Name & " " & user.Id & " " & user.Age)
Next
出力結果
Hanako as88 25
Yoko oy90 25
Kou ko32 25
Taro zx33 30
Dai bu12 30
Taro ko32 30
年齢の昇順でソートされました。
降順にしたい時は
Return a.Age - b.Age を
Return b.Age - a.Age
に変えればOKです。
#5.複数のキーでソートする
年齢が同じ場合に名前でソートしたい場合には
以下のような比較メソッドを用意します。
Private Function CompareByAgeName(ByVal a As User, ByVal b As User) As Integer
If a.Age - b.Age = 0 Then
Return String.Compare(a.Name, b.Name)
End If
Return a.Age - b.Age
End Function
String.Compareは標準関数で
2つの文字列を比較して相対位置を並べ替え順序で示す整数を返してくれます。
この比較メソッドをを使ってソートすると
'年齢の昇順、名前の昇順でソート
users.Sort(AddressOf Me.CompareByAgeName)
'リストに入っているユーザーの名前、ID、年齢を順番に表示
For Each user In users
Debug.Print(user.Name & " " & user.Id & " " & user.Age)
Next
出力結果
Hanako as88 25
Kou ko32 25
Yoko oy90 25
Dai bu12 30
Taro zx33 30
Taro ko32 30
更に年齢、名前が同じでIDの違う Taro 30歳 が2人います。
この2人をIDの昇順にソートしたい場合は
比較メソッドを次のようにします。
Private Function CompareByAgeNameId(ByVal a As User, ByVal b As User) As Integer
If a.Age - b.Age = 0 And String.Compare(a.Name, b.Name) = 0 Then
Return String.Compare(a.Id, b.Id)
End If
If a.Age - b.Age = 0 Then
Return String.Compare(a.Name, b.Name)
End If
Return a.Age - b.Age
End Function
この比較メソッドを使ってソートすると
'年齢の昇順、名前の昇順、IDの昇順でソート
users.Sort(AddressOf Me.CompareByAgeNameId)
'リストに入っているユーザーの名前、ID、年齢を順番に表示
For Each user In users
Debug.Print(user.Name & " " & user.Id & " " & user.Age)
Next
出力結果
Hanako as88 25
Kou ko32 25
Yoko oy90 25
Dai bu12 30
Taro ko32 30
Taro zx33 30
Taro 30歳の2人をIDの昇順でソートできました。
#参考記事
VB.NET 独自クラスの配列や List(T) を任意にソートする
http://programmers.high-way.info/vb/list-sort.html