ここでは非ジェネリックなコレクション型System.Collections.SortedListクラスについて解説します。 SortedListクラスを使用するよりも、SortedListに相当するジェネリックなコレクション型System.Collections.Generic.SortedList<T>クラスを使用することを強く推奨します。

SortedList

System.Collections.SortedListクラスは、HashtableクラスArrayListクラスの両方の特徴を持ったコレクションです。 Hashtableと同じようにキーと値のペアで要素が格納され、キーによってコレクション内の要素にアクセスできるという点に加え、ArrayListのようにインデックスを指定して要素にアクセスすることができます。 また、SortedListという名前が示すとおり、要素が追加される時点でSortedListの内容はキーに基づいてソートされる点でHashtableと異なります。

基本的な操作

多くの操作はHashtableと同様ですが、SortedListを使った例によって基本的な操作について見ていきます。

using System;
using System.Collections;

class Sample {
  static void Main()
  {
    SortedList list = new SortedList();

    // キーを"foo"として値16を追加
    list.Add("foo", 16);

    list["bar"] = 72; // キー"bar"の値として値72を設定

    Console.WriteLine("foo => {0}", list["foo"]); // キー"foo"の値を取得
    Console.WriteLine("bar => {0}", list["bar"]); // キー"bar"の値を取得

    Console.WriteLine("0 = {0}", list.GetByIndex(0)); // インデックス0の要素の値を取得
    Console.WriteLine("1 = {0}", list.GetByIndex(1)); // インデックス1の要素の値を取得

    // インデックス1の要素の値を取得
    list.SetByIndex(1, "hoge");

    Console.WriteLine("foo => {0}", list["foo"]); // キー"foo"の値を取得
    Console.WriteLine("bar => {0}", list["bar"]); // キー"bar"の値を取得

    // キー"foo", "bar"の要素が格納されているインデックスを取得
    Console.WriteLine("IndexOfKey 'foo' => {0}", list.IndexOfKey("foo"));
    Console.WriteLine("IndexOfKey 'bar' => {0}", list.IndexOfKey("bar"));

    // 値16, 72の要素が格納されているインデックスを取得
    Console.WriteLine("IndexOfValue 16 => {0}", list.IndexOfValue(16));
    Console.WriteLine("IndexOfValue 72 => {0}", list.IndexOfValue(72));
  }
}
Imports System
Imports System.Collections

Class Sample
  Shared Sub Main()
    Dim list As New SortedList()

    ' キーを"foo"として値16を追加
    list.Add("foo", 16)

    list("bar") = 72 ' キー"bar"の値として値72を設定

    Console.WriteLine("foo => {0}", list("foo")) ' キー"foo"の値を取得
    Console.WriteLine("bar => {0}", list("bar")) ' キー"bar"の値を取得

    Console.WriteLine("0 = {0}", list.GetByIndex(0)) ' インデックス0の要素の値を取得
    Console.WriteLine("1 = {0}", list.GetByIndex(1)) ' インデックス1の要素の値を取得

    ' インデックス1の要素の値を取得
    list.SetByIndex(1, "hoge")

    Console.WriteLine("foo => {0}", list("foo")) ' キー"foo"の値を取得
    Console.WriteLine("bar => {0}", list("bar")) ' キー"bar"の値を取得

    ' キー"foo", "bar"の要素が格納されているインデックスを取得
    Console.WriteLine("IndexOfKey 'foo' => {0}", list.IndexOfKey("foo"))
    Console.WriteLine("IndexOfKey 'bar' => {0}", list.IndexOfKey("bar"))

    ' 値16, 72の要素が格納されているインデックスを取得
    Console.WriteLine("IndexOfValue 16 => {0}", list.IndexOfValue(16))
    Console.WriteLine("IndexOfValue 72 => {0}", list.IndexOfValue(72))
  End Sub
End Class
実行結果
foo => 16
bar => 72
0 = 72
1 = 16
foo => hoge
bar => 72
IndexOfKey 'foo' => 1
IndexOfKey 'bar' => 0
IndexOfValue 16 => -1
IndexOfValue 72 => 0

例で示したとおり、キーによるアクセスの場合はHashtableと同様にインデクサを用いて行い、インデックスによるアクセスの場合はGetByIndexメソッドSetByIndexメソッドを用いて行います。 インデクサにインデックスを指定しても、キーとしてしか扱われないので注意してください。

また、キーに該当する要素のインデックス、値に該当する要素のインデックスを取得するには、IndexOfKeyメソッドIndexOfValueメソッドを使います。 該当するキーまたは値が見つからない場合は-1が返されます。

この例では使用していませんが、キーによる要素の削除にはRemoveメソッド、インデックスによる要素の削除にはRemoveAtメソッドを使用します。 Hashtableと同様、ContainsKeyメソッドContainsValueメソッドも用意されています。

列挙操作

SortedListの列挙もHashtableでの列挙と同様、DictionaryEntryに格納たキーと値のペアで列挙されますが、ソート済みの状態で列挙される点がHashtableとは異なります。 また、Hashtableと同様に、SortedListに格納されているすべてのキーはKeysプロパティ、値はValuesプロパティを通して参照できます。

using System;
using System.Collections;

class Sample {
  static void Main()
  {
    SortedList list = new SortedList();

    list["foo"] = 16;
    list["bar"] = 72;
    list["baz"] = 42;

    // SortedListに格納されているキーと値のペアを列挙
    Console.WriteLine("SortedList");

    foreach (DictionaryEntry entry in list) {
      Console.WriteLine("{0} => {1}", entry.Key, entry.Value);
    }

    // 同じ内容のHashtableを作成して列挙
    Hashtable hash = new Hashtable(list);

    Console.WriteLine("Hashtable");

    foreach (DictionaryEntry entry in hash) {
      Console.WriteLine("{0} => {1}", entry.Key, entry.Value);
    }

    // SortedListに格納されているすべてのキーを列挙
    Console.WriteLine("[Keys]");

    foreach (object key in list.Keys) {
      Console.WriteLine(key);
    }

    // SortedListに格納されているすべての値を列挙
    Console.WriteLine("[Values]");

    foreach (object val in list.Values) {
      Console.WriteLine(val);
    }
  }
}
Imports System
Imports System.Collections

Class Sample
  Shared Sub Main()
    Dim list As New SortedList()

    list("foo") = 16
    list("bar") = 72
    list("baz") = 42

    ' SortedListに格納されているキーと値のペアを列挙
    Console.WriteLine("SortedList")

    For Each entry As DictionaryEntry In list
      Console.WriteLine("{0} => {1}", entry.Key, entry.Value)
    Next

    ' 同じ内容のHashtableを作成して列挙
    Dim hash As New Hashtable(list)

    Console.WriteLine("Hashtable")

    For Each entry As DictionaryEntry In hash
      Console.WriteLine("{0} => {1}", entry.Key, entry.Value)
    Next

    ' SortedListに格納されているすべてのキーを列挙
    Console.WriteLine("[Keys]")

    For Each key As Object In list.Keys
      Console.WriteLine(key)
    Next

    ' SortedListに格納されているすべての値を列挙
    Console.WriteLine("[Values]")

    For Each val As Object In list.Values
      Console.WriteLine(val)
    Next
  End Sub
End Class
実行結果
SortedList
bar => 72
baz => 42
foo => 16
Hashtable
foo => 16
baz => 42
bar => 72
[Keys]
bar
baz
foo
[Values]
72
42
16

同じ内容のSortedListとHashtableを列挙していますが、SortedListの場合はキーによってソートされている点に注目してください。

ソート順のカスタマイズ

コンストラクタで適切なIComparerインターフェイスを指定することで、SortedListのキー比較時の動作をカスタマイズ出来ます。 HashtableではIEqualityComparerインターフェイスを用いてキーの同一性の比較のみを行いますが、SortedListではIComparerインターフェイスを使ってキーの同一性の比較と並べ替えを行います。 以下は、アルファベット順とは逆順(Z-Aの順)になるようにソートするIComparerを実装し、SortedListでの並べ替え順をカスタマイズする例です。

using System;
using System.Collections;

// アルファベット順とは逆順にソートするためのIComparer
class ReverseStringComparer : IComparer {
  public int Compare(object x, object y)
  {
    // StringComparer.CurrentCulture.Compareとは逆の結果を返すようにする
    return -1 * StringComparer.CurrentCulture.Compare(x, y);
  }
}

class Sample {
  static void Main()
  {
    SortedList orderdList = new SortedList(StringComparer.CurrentCulture);

    orderdList["Alice"]    = 1;
    orderdList["Bob"]      = 2;
    orderdList["Charlie"]  = 3;
    orderdList["Dave"]     = 4;

    SortedList reverseOrderdList = new SortedList(new ReverseStringComparer());

    reverseOrderdList["Alice"]    = 1;
    reverseOrderdList["Bob"]      = 2;
    reverseOrderdList["Charlie"]  = 3;
    reverseOrderdList["Dave"]     = 4;

    Console.WriteLine("orderdList");

    foreach (DictionaryEntry entry in orderdList) {
      Console.WriteLine("{0,-7} => {1}", entry.Key, entry.Value);
    }

    Console.WriteLine("reverseOrderdList");

    foreach (DictionaryEntry entry in reverseOrderdList) {
      Console.WriteLine("{0,-7} => {1}", entry.Key, entry.Value);
    }
  }
}
Imports System
Imports System.Collections

' アルファベット順とは逆順にソートするためのIComparer
Class ReverseStringComparer
  Implements IComparer

  Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements IComparer.Compare
    ' StringComparer.CurrentCulture.Compareとは逆の結果を返すようにする
    Return -1 * StringComparer.CurrentCulture.Compare(x, y)
  End Function
End Class

Class Sample
  Shared Sub Main()
    Dim orderdList As New SortedList(StringComparer.CurrentCulture)

    orderdList("Alice")    = 1
    orderdList("Bob")      = 2
    orderdList("Charlie")  = 3
    orderdList("Dave")     = 4

    Dim reverseOrderdList As New SortedList(New ReverseStringComparer())

    reverseOrderdList("Alice")    = 1
    reverseOrderdList("Bob")      = 2
    reverseOrderdList("Charlie")  = 3
    reverseOrderdList("Dave")     = 4

    Console.WriteLine("orderdList")

    For Each entry As DictionaryEntry In orderdList
      Console.WriteLine("{0,-7} => {1}", entry.Key, entry.Value)
    Next

    Console.WriteLine("reverseOrderdList")

    For Each entry As DictionaryEntry In reverseOrderdList
      Console.WriteLine("{0,-7} => {1}", entry.Key, entry.Value)
    Next
  End Sub
End Class
実行結果
orderdList
Alice   => 1
Bob     => 2
Charlie => 3
Dave    => 4
reverseOrderdList
Dave    => 4
Charlie => 3
Bob     => 2
Alice   => 1