- ジェネリックコレクション ページ一覧
SortedListとSortedDictionary
System.Collections.Generic.SortedListクラスとSystem.Collections.Generic.SortedDictionaryクラスは非常によく似たコレクションクラスです。 どちらもDictionaryクラスと同じようにキーと値の対(ペア)で要素を格納します。 キーを指定することにより、そのキーに対応する要素の値を取得することができます。
SortedListクラス・SortedDictionaryクラスでは、要素が設定(追加)される時点でキーに基づいて自動的に要素の並べ替え(ソート)が行われます。 これはDictionaryには無い機能です。 Sortedの名前が示す通り、格納される要素は常にソートされた状態になります。
これらの特徴はSortedListとSortedDictionaryに共通するものですが、SortedListとSortedDictionaryの相違点の1つにインデックスを指定したアクセスができるかどうかがあります。
SortedListは名前が示すとおりListと似た特徴を持ち、インデックスを指定してキーや値を取得したり、逆にキーや値からインデックスを検索したりすることができます。 一方、SortedDictionaryはDictionaryと同様にインデックスを指定したアクセスはできません。 このような特徴と関連して、要素の挿入・削除操作の速度やメモリ使用量などのパフォーマンス面にも違いが現れます。
SortedListに格納される要素に割り振られるインデックスは、あくまで各要素を並べ替えた時の順序となります。 Listのように要素を追加した順にインデックスが割り振られるわけではありません。 キー・値のペアで要素を格納し、かつ要素を追加した順にインデックスを割り振りたい場合はOrderedDictionaryクラスを使います。
基本操作
インスタンスの作成・要素の取得・設定・列挙
インスタンスの作成、要素の取得と設定、要素の列挙などの操作はDictionaryクラスを使う場合と変わりありません。 foreach文で列挙を行う際にソートされた状態で列挙される点のみが異なります。
using System;
using System.Collections.Generic;
class Sample {
static void Main()
{
// インスタンスの作成
SortedList<string, int> list = new SortedList<string, int>();
// 要素の設定
list["Dave"] = 1;
list["Alice"] = 2;
list["Bob"] = 3;
list["Eve"] = 4;
list["Charlie"] = 5;
// 格納されている要素の列挙
foreach (KeyValuePair<string, int> pair in list) {
Console.WriteLine("{0,-8} => {1}", pair.Key, pair.Value);
}
}
}
Imports System
Imports System.Collections.Generic
Class Sample
Shared Sub Main()
' インスタンスの作成
Dim list As New SortedList(Of String, Integer)()
' 要素の設定
list("Dave") = 1
list("Alice") = 2
list("Bob") = 3
list("Eve") = 4
list("Charlie") = 5
' 格納されている要素の列挙
For Each pair As KeyValuePair(Of String, Integer) In list
Console.WriteLine("{0,-8} => {1}", pair.Key, pair.Value)
Next
End Sub
End Class
using System;
using System.Collections.Generic;
class Sample {
static void Main()
{
// インスタンスの作成
SortedDictionary<string, int> dict = new SortedDictionary<string, int>();
// 要素の設定
dict["Dave"] = 1;
dict["Alice"] = 2;
dict["Bob"] = 3;
dict["Eve"] = 4;
dict["Charlie"] = 5;
// 格納されている要素の列挙
foreach (KeyValuePair<string, int> pair in dict) {
Console.WriteLine("{0,-8} => {1}", pair.Key, pair.Value);
}
}
}
Imports System
Imports System.Collections.Generic
Class Sample
Shared Sub Main()
' インスタンスの作成
Dim dict As New SortedDictionary(Of String, Integer)()
' 要素の設定
dict("Dave") = 1
dict("Alice") = 2
dict("Bob") = 3
dict("Eve") = 4
dict("Charlie") = 5
' 格納されている要素の列挙
For Each pair As KeyValuePair(Of String, Integer) In dict
Console.WriteLine("{0,-8} => {1}", pair.Key, pair.Value)
Next
End Sub
End Class
Alice => 2 Bob => 3 Charlie => 5 Dave => 1 Eve => 4
Keysプロパティを列挙した場合も同様に、キーがソートされた状態で列挙されます。 Valuesプロパティを列挙した場合は、ソートされたキーと同じ順序でキーに対応する値が列挙されます(値単独でソートされた順序にはなりません)。
using System;
using System.Collections.Generic;
class Sample {
static void Main()
{
// インスタンスの作成
SortedList<string, int> list = new SortedList<string, int>();
// 要素の設定
list["Dave"] = 1;
list["Alice"] = 2;
list["Bob"] = 3;
list["Eve"] = 4;
list["Charlie"] = 5;
// 格納されているキーの列挙
foreach (string key in list.Keys) {
Console.WriteLine(key);
}
// 格納されている値の列挙
foreach (int val in list.Values) {
Console.WriteLine(val);
}
}
}
Imports System
Imports System.Collections.Generic
Class Sample
Shared Sub Main()
' インスタンスの作成
Dim list As New SortedList(Of String, Integer)()
' 要素の設定
list("Dave") = 1
list("Alice") = 2
list("Bob") = 3
list("Eve") = 4
list("Charlie") = 5
' 格納されているキーの列挙
For Each key As String In list.Keys
Console.WriteLine(key)
Next
' 格納されている値の列挙
For Each value As Integer In list.Values
Console.WriteLine(value)
Next
End Sub
End Class
using System;
using System.Collections.Generic;
class Sample {
static void Main()
{
// インスタンスの作成
SortedDictionary<string, int> dict = new SortedDictionary<string, int>();
// 要素の設定
dict["Dave"] = 1;
dict["Alice"] = 2;
dict["Bob"] = 3;
dict["Eve"] = 4;
dict["Charlie"] = 5;
// 格納されているキーの列挙
foreach (string key in dict.Keys) {
Console.WriteLine(key);
}
// 格納されている値の列挙
foreach (int val in dict.Values) {
Console.WriteLine(val);
}
}
}
Imports System
Imports System.Collections.Generic
Class Sample
Shared Sub Main()
' インスタンスの作成
Dim dict As New SortedDictionary(Of String, Integer)()
' 要素の設定
dict("Dave") = 1
dict("Alice") = 2
dict("Bob") = 3
dict("Eve") = 4
dict("Charlie") = 5
' 格納されているキーの列挙
For Each key As String In dict.Keys
Console.WriteLine(key)
Next
' 格納されている値の列挙
For Each value As Integer In dict.Values
Console.WriteLine(value)
Next
End Sub
End Class
Alice Bob Charlie Dave Eve 2 3 5 1 4
コレクション初期化子
Dictionaryの場合と同様、SortedList・SortedDictionaryでもコレクション初期化子を使ってインスタンスの作成と要素の追加を同時に行うことができます。 コレクション初期化子はC# 3.0(Visual C# 2008)以降、VB 10(Visual Basic 2010)以降でサポートされます。
using System;
using System.Collections.Generic;
class Sample {
static void Main()
{
// コレクション初期化子を使ってインスタンスの作成と要素の追加を行う
SortedList<string, int> list = new SortedList<string, int>() {
{"Dave", 1},
{"Alice", 2},
{"Bob", 3},
{"Eve", 4},
{"Charlie", 5},
};
Console.WriteLine("Count = {0}", list.Count);
Console.WriteLine("Eve => {0}", list["Eve"]);
}
}
Imports System
Imports System.Collections.Generic
Class Sample
Shared Sub Main()
' コレクション初期化子を使ってインスタンスの作成と要素の追加を行う
Dim list As New SortedList(Of String, Integer)() From {
{"Dave", 1},
{"Alice", 2},
{"Bob", 3},
{"Eve", 4},
{"Charlie", 5}
}
Console.WriteLine("Count = {0}", list.Count)
Console.WriteLine("Eve => {0}", list("Eve"))
End Sub
End Class
using System;
using System.Collections.Generic;
class Sample {
static void Main()
{
// コレクション初期化子を使ってインスタンスの作成と要素の追加を行う
SortedDictionary<string, int> dict = new SortedDictionary<string, int>() {
{"Dave", 1},
{"Alice", 2},
{"Bob", 3},
{"Eve", 4},
{"Charlie", 5},
};
Console.WriteLine("Count = {0}", dict.Count);
Console.WriteLine("Eve => {0}", dict["Eve"]);
}
}
Imports System
Imports System.Collections.Generic
Class Sample
Shared Sub Main()
' コレクション初期化子を使ってインスタンスの作成と要素の追加を行う
Dim dict As New SortedDictionary(Of String, Integer)() From {
{"Dave", 1},
{"Alice", 2},
{"Bob", 3},
{"Eve", 4},
{"Charlie", 5}
}
Console.WriteLine("Count = {0}", dict.Count)
Console.WriteLine("Eve => {0}", dict("Eve"))
End Sub
End Class
Count = 5 Eve => 4
存在しないキーを参照した場合・既にキーが存在する場合
存在しないキーを参照した場合の動作はDictionaryと同様で、例外KeyNotFoundExceptionがスローされます。
using System;
using System.Collections.Generic;
class Sample {
static void Main()
{
SortedList<string, int> list = new SortedList<string, int>();
list["foo"] = 16;
list["bar"] = 72;
// 存在するキーに対応する値を取得
Console.WriteLine("foo = {0}", list["foo"]);
Console.WriteLine("bar = {0}", list["bar"]);
// 存在しないキー"hoge"に対応する値を取得
Console.WriteLine("hoge = {0}", list["hoge"]);
}
}
Imports System
Imports System.Collections.Generic
Class Sample
Shared Sub Main()
Dim list As New SortedList(Of String, Integer)()
list("foo") = 16
list("bar") = 72
' 存在するキーに対応する値を取得
Console.WriteLine("foo = {0}", list("foo"))
Console.WriteLine("bar = {0}", list("bar"))
' 存在しないキー"hoge"に対応する値を取得
Console.WriteLine("hoge = {0}", list("hoge"))
End Sub
End Class
using System;
using System.Collections.Generic;
class Sample {
static void Main()
{
SortedDictionary<string, int> dict = new SortedDictionary<string, int>();
dict["foo"] = 16;
dict["bar"] = 72;
// 存在するキーに対応する値を取得
Console.WriteLine("foo = {0}", dict["foo"]);
Console.WriteLine("bar = {0}", dict["bar"]);
// 存在しないキー"hoge"に対応する値を取得
Console.WriteLine("hoge = {0}", dict["hoge"]);
}
}
Imports System
Imports System.Collections.Generic
Class Sample
Shared Sub Main()
Dim dict As New SortedDictionary(Of String, Integer)()
dict("foo") = 16
dict("bar") = 72
' 存在するキーに対応する値を取得
Console.WriteLine("foo = {0}", dict("foo"))
Console.WriteLine("bar = {0}", dict("bar"))
' 存在しないキー"hoge"に対応する値を取得
Console.WriteLine("hoge = {0}", dict("hoge"))
End Sub
End Class
foo = 16 bar = 72 ハンドルされていない例外: System.Collections.Generic.KeyNotFoundException: 指定されたキーはディレクトリ内に存在しませんでした。 場所 System.Collections.Generic.SortedDictionary`2.get_Item(TKey key) 場所 Sample.Main()
キーを指定した上書き・追加の動作もDictionaryと同様です。 インデクサで既に存在するキーを指定した場合は値が上書きされ、Addメソッドで既に存在するキーを指定した場合は例外ArgumentExceptionがスローされます。
using System;
using System.Collections.Generic;
class Sample {
static void Main()
{
SortedList<string, int> list = new SortedList<string, int>();
list["foo"] = 16;
Console.WriteLine("foo = {0}", list["foo"]);
// 既に存在するキーを指定して値を上書き
list["foo"] = 72;
Console.WriteLine("foo = {0}", list["foo"]);
// 既に存在するキーを指定して値を追加
list.Add("foo", 42);
Console.WriteLine("foo = {0}", list["foo"]);
}
}
Imports System
Imports System.Collections.Generic
Class Sample
Shared Sub Main()
Dim list As New SortedList(Of String, Integer)()
list("foo") = 16
Console.WriteLine("foo = {0}", list("foo"))
' 既に存在するキーを指定して値を上書き
list("foo") = 72
Console.WriteLine("foo = {0}", list("foo"))
' 既に存在するキーを指定して値を追加
list.Add("foo", 42)
Console.WriteLine("foo = {0}", list("foo"))
End Sub
End Class
using System;
using System.Collections.Generic;
class Sample {
static void Main()
{
SortedDictionary<string, int> dict = new SortedDictionary<string, int>();
dict["foo"] = 16;
Console.WriteLine("foo = {0}", dict["foo"]);
// 既に存在するキーを指定して値を上書き
dict["foo"] = 72;
Console.WriteLine("foo = {0}", dict["foo"]);
// 既に存在するキーを指定して値を追加
dict.Add("foo", 42);
Console.WriteLine("foo = {0}", dict["foo"]);
}
}
Imports System
Imports System.Collections.Generic
Class Sample
Shared Sub Main()
Dim dict As New SortedDictionary(Of String, Integer)()
dict("foo") = 16
Console.WriteLine("foo = {0}", dict("foo"))
' 既に存在するキーを指定して値を上書き
dict("foo") = 72
Console.WriteLine("foo = {0}", dict("foo"))
' 既に存在するキーを指定して値を追加
dict.Add("foo", 42)
Console.WriteLine("foo = {0}", dict("foo"))
End Sub
End Class
foo = 16 foo = 72 ハンドルされていない例外: System.ArgumentException: 同一のキーを含む項目が既に追加されています。 場所 System.ThrowHelper.ThrowArgumentException(ExceptionResource resource) 場所 System.Collections.Generic.TreeSet`1.AddIfNotPresent(T item) 場所 System.Collections.Generic.SortedDictionary`2.Add(TKey key, TValue value) 場所 Sample.Main()
要素の検索・削除・存在チェック
Dictionaryクラスと同様、ContainsKeyメソッドやTryGetValueメソッドなどを使うことができます。
using System;
using System.Collections.Generic;
class Sample {
static void Main()
{
SortedList<string, int> list = new SortedList<string, int>();
list["foo"] = 16;
list["bar"] = 72;
list["baz"] = 42;
// キー"foo"を持つ要素があるかどうか
Console.WriteLine(list.ContainsKey("foo"));
// 値9を持つ要素があるかどうか
Console.WriteLine(list.ContainsValue(9));
// キー"bar"の要素を削除
list.Remove("bar");
foreach (KeyValuePair<string, int> pair in list) {
Console.WriteLine("{0} => {1}", pair.Key, pair.Value);
}
// キー"baz"に該当する値を取得
int valueOfBaz;
if (list.TryGetValue("baz", out valueOfBaz)) {
Console.WriteLine("value of 'baz': {0}", valueOfBaz);
}
else {
Console.WriteLine("key not found");
}
// キー"hoge"に該当する値を取得
int valueOfHoge;
if (list.TryGetValue("hoge", out valueOfHoge)) {
Console.WriteLine("value of 'hoge': {0}", valueOfHoge);
}
else {
Console.WriteLine("key not found");
}
}
}
Imports System
Imports System.Collections.Generic
Class Sample
Shared Sub Main()
Dim list As New SortedList(Of String, Integer)()
list("foo") = 16
list("bar") = 72
list("baz") = 42
' キー"foo"を持つ要素があるかどうか
Console.WriteLine(list.ContainsKey("foo"))
' 値9を持つ要素があるかどうか
Console.WriteLine(list.ContainsValue(9))
' キー"bar"の要素を削除
list.Remove("bar")
For Each pair As KeyValuePair(Of String, Integer) In list
Console.WriteLine("{0} => {1}", pair.Key, pair.Value)
Next
' キー"baz"に該当する値を取得
Dim valueOfBaz As Integer
If list.TryGetValue("baz", valueOfBaz) Then
Console.WriteLine("value of 'baz': {0}", valueOfBaz)
Else
Console.WriteLine("key not found")
End If
' キー"hoge"に該当する値を取得
Dim valueOfHoge As Integer
If list.TryGetValue("hoge", valueOfHoge) Then
Console.WriteLine("value of 'hoge': {0}", valueOfHoge)
Else
Console.WriteLine("key not found")
End If
End Sub
End Class
using System;
using System.Collections.Generic;
class Sample {
static void Main()
{
SortedDictionary<string, int> dict = new SortedDictionary<string, int>();
dict["foo"] = 16;
dict["bar"] = 72;
dict["baz"] = 42;
// キー"foo"を持つ要素があるかどうか
Console.WriteLine(dict.ContainsKey("foo"));
// 値9を持つ要素があるかどうか
Console.WriteLine(dict.ContainsValue(9));
// キー"bar"の要素を削除
dict.Remove("bar");
foreach (KeyValuePair<string, int> pair in dict) {
Console.WriteLine("{0} => {1}", pair.Key, pair.Value);
}
// キー"baz"に該当する値を取得
int valueOfBaz;
if (dict.TryGetValue("baz", out valueOfBaz)) {
Console.WriteLine("value of 'baz': {0}", valueOfBaz);
}
else {
Console.WriteLine("key not found");
}
// キー"hoge"に該当する値を取得
int valueOfHoge;
if (dict.TryGetValue("hoge", out valueOfHoge)) {
Console.WriteLine("value of 'hoge': {0}", valueOfHoge);
}
else {
Console.WriteLine("key not found");
}
}
}
Imports System
Imports System.Collections.Generic
Class Sample
Shared Sub Main()
Dim dict As New SortedDictionary(Of String, Integer)()
dict("foo") = 16
dict("bar") = 72
dict("baz") = 42
' キー"foo"を持つ要素があるかどうか
Console.WriteLine(dict.ContainsKey("foo"))
' 値9を持つ要素があるかどうか
Console.WriteLine(dict.ContainsValue(9))
' キー"bar"の要素を削除
dict.Remove("bar")
For Each pair As KeyValuePair(Of String, Integer) In dict
Console.WriteLine("{0} => {1}", pair.Key, pair.Value)
Next
' キー"baz"に該当する値を取得
Dim valueOfBaz As Integer
If dict.TryGetValue("baz", valueOfBaz) Then
Console.WriteLine("value of 'baz': {0}", valueOfBaz)
Else
Console.WriteLine("key not found")
End If
' キー"hoge"に該当する値を取得
Dim valueOfHoge As Integer
If dict.TryGetValue("hoge", valueOfHoge) Then
Console.WriteLine("value of 'hoge': {0}", valueOfHoge)
Else
Console.WriteLine("key not found")
End If
End Sub
End Class
True False baz => 42 foo => 16 value of 'baz': 42 key not found
SortedListのみでサポートされる操作
SortedListとSortedDictionaryの相違点の一つとして、SortedListではインデックスを使った操作ができるという点が挙げられます。 以下の操作はSortedListのみで提供されるもので、SortedDictionaryでは提供されないものです。
インデックスを指定した操作
SortedListクラスでは、インデックスを指定してキー・値へアクセスすることができます。 KeysプロパティおよびValuesプロパティでは、インデックスを指定することで個々の要素のキーと値を取得できます。
using System;
using System.Collections.Generic;
class Sample {
static void Main()
{
SortedList<string, int> list = new SortedList<string, int>();
list["Dave"] = 1;
list["Alice"] = 2;
list["Bob"] = 3;
list["Eve"] = 4;
list["Charlie"] = 5;
for (int i = 0; i < list.Count; i++) {
// インデックスを指定してキーと値を取得
Console.WriteLine("[{0}] {1,-8} => {2}", i, list.Keys[i], list.Values[i]);
}
}
}
Imports System
Imports System.Collections.Generic
Class Sample
Shared Sub Main()
Dim list As New SortedList(Of String, Integer)()
list("Dave") = 1
list("Alice") = 2
list("Bob") = 3
list("Eve") = 4
list("Charlie") = 5
For i As Integer = 0 To list.Count - 1
' インデックスを指定してキーと値を取得
Console.WriteLine("[{0}] {1,-8} => {2}", i, list.Keys(i), list.Values(i))
Next
End Sub
End Class
[0] Alice => 2 [1] Bob => 3 [2] Charlie => 5 [3] Dave => 1 [4] Eve => 4
なお、Keysプロパティ・Valuesプロパティを使ってインデックスを指定した値・キーの設定は行うことはできません。
SortedListでは、ソートされた順に従って各要素にインデックスが割り振られます(要素が追加された順ではありません)。 インデックス0の要素は、並べ替えた際に最初に位置する要素となります。 要素の追加や削除が行われる度に並べ替えられるため、要素に割り振られていたインデックスが変わることもあります。
using System;
using System.Collections.Generic;
class Sample {
static void Main()
{
SortedList<string, int> list = new SortedList<string, int>();
list["Dave"] = 1;
list["Bob"] = 3;
// インデックス0のキーと値を取得
Console.WriteLine("{0,-8} => {1}", list.Keys[0], list.Values[0]);
// 要素を削除
list.Remove("Bob");
// インデックス0のキーと値を取得
Console.WriteLine("{0,-8} => {1}", list.Keys[0], list.Values[0]);
// 要素を追加
list.Add("Alice", 2);
// インデックス0のキーと値を取得
Console.WriteLine("{0,-8} => {1}", list.Keys[0], list.Values[0]);
}
}
Imports System
Imports System.Collections.Generic
Class Sample
Shared Sub Main()
Dim list As New SortedList(Of String, Integer)()
list("Dave") = 1
list("Bob") = 3
' インデックス0のキーと値を取得
Console.WriteLine("{0,-8} => {1}", list.Keys(0), list.Values(0))
' 要素を削除
list.Remove("Bob")
' インデックス0のキーと値を取得
Console.WriteLine("{0,-8} => {1}", list.Keys(0), list.Values(0))
' 要素を追加
list.Add("Alice", 2)
' インデックス0のキーと値を取得
Console.WriteLine("{0,-8} => {1}", list.Keys(0), list.Values(0))
End Sub
End Class
Bob => 3 Dave => 1 Alice => 2
キーと値のペアを格納するコレクションで、かつ要素が追加された順でインデックスが割り振られるようなコレクションが必要な場合は、OrderedDictionaryクラスを使うことができます。 ただし、このコレクションは非ジェネリックコレクションです。 ジェネリック版OrderedDictionaryではジェネリック版のOrderedDictionaryを実装したものを掲載しています。
キーまたは値からインデックスを取得する
キーや値からインデックスを取得したい場合は、IndexOfKeyメソッドおよびIndexOfValueメソッドを使うことでキー・値のインデックスを取得することができます。 SortedListに該当するキー・値が存在しない場合は-1が返されます。
using System;
using System.Collections.Generic;
class Sample {
static void Main()
{
SortedList<string, int> list = new SortedList<string, int>();
list["Dave"] = 1;
list["Alice"] = 2;
list["Bob"] = 3;
list["Eve"] = 4;
list["Charlie"] = 5;
// インデックス・キー・値の一覧を表示
for (int i = 0; i < list.Count; i++) {
Console.WriteLine("[{0}] {1,-8} => {2}", i, list.Keys[i], list.Values[i]);
}
Console.WriteLine();
// キー"Charlie"を持つ要素のインデックスを取得
Console.WriteLine("IndexOfKey 'Charlie': {0}", list.IndexOfKey("Charlie"));
// 値2を持つ要素のインデックスを取得
Console.WriteLine("IndexOfValue 2: {0}", list.IndexOfValue(2));
// 値42を持つ要素のインデックスを取得
Console.WriteLine("IndexOfValue 42: {0}", list.IndexOfValue(42));
}
}
Imports System
Imports System.Collections.Generic
Class Sample
Shared Sub Main()
Dim list As New SortedList(Of String, Integer)()
list("Dave") = 1
list("Alice") = 2
list("Bob") = 3
list("Eve") = 4
list("Charlie") = 5
' インデックス・キー・値の一覧を表示
For i As Integer = 0 To list.Count - 1
Console.WriteLine("[{0}] {1,-8} => {2}", i, list.Keys(i), list.Values(i))
Next
Console.WriteLine()
' キー"Charlie"を持つ要素のインデックスを取得
Console.WriteLine("IndexOfKey 'Charlie': {0}", list.IndexOfKey("Charlie"))
' 値2を持つ要素のインデックスを取得
Console.WriteLine("IndexOfValue 2: {0}", list.IndexOfValue(2))
' 値42を持つ要素のインデックスを取得
Console.WriteLine("IndexOfValue 42: {0}", list.IndexOfValue(42))
End Sub
End Class
[0] Alice => 2 [1] Bob => 3 [2] Charlie => 5 [3] Dave => 1 [4] Eve => 4 IndexOfKey 'Charlie': 2 IndexOfValue 2: 0 IndexOfValue 42: -1
インデックスを指定して要素を削除する
SortedListでは、Removeメソッドによるキーを指定した要素の削除の他に、RemoveAtメソッドによるインデックスを指定した要素の削除を行うことができます。
using System;
using System.Collections.Generic;
class Sample {
static void Main()
{
SortedList<string, int> list = new SortedList<string, int>();
list["Dave"] = 1;
list["Alice"] = 2;
list["Bob"] = 3;
list["Eve"] = 4;
list["Charlie"] = 5;
for (int i = 0; i < list.Count; i++) {
Console.WriteLine("[{0}] {1,-8} => {2}", i, list.Keys[i], list.Values[i]);
}
Console.WriteLine();
// インデックス3の要素を削除
list.RemoveAt(3);
for (int i = 0; i < list.Count; i++) {
Console.WriteLine("[{0}] {1,-8} => {2}", i, list.Keys[i], list.Values[i]);
}
}
}
Imports System
Imports System.Collections.Generic
Class Sample
Shared Sub Main()
Dim list As New SortedList(Of String, Integer)()
list("Dave") = 1
list("Alice") = 2
list("Bob") = 3
list("Eve") = 4
list("Charlie") = 5
For i As Integer = 0 To list.Count - 1
Console.WriteLine("[{0}] {1,-8} => {2}", i, list.Keys(i), list.Values(i))
Next
Console.WriteLine()
' インデックス3の要素を削除
list.RemoveAt(3)
For i As Integer = 0 To list.Count - 1
Console.WriteLine("[{0}] {1,-8} => {2}", i, list.Keys(i), list.Values(i))
Next
End Sub
End Class
[0] Alice => 2 [1] Bob => 3 [2] Charlie => 5 [3] Dave => 1 [4] Eve => 4 [0] Alice => 2 [1] Bob => 3 [2] Charlie => 5 [3] Eve => 4
キー比較・ソート順のカスタマイズ
SortedList・SortedDictionaryにはSortメソッドやReverseメソッドなどコレクションに格納されている要素の順序を並べ替えるメソッドは用意されていません。 そのため、一度インスタンスを作成すると後から並べ替え順序を変更することはできません。
SortedList・SortedDictionaryでは、コンストラクタで適切なIComparer<T>インターフェイスを指定することでキーの比較や並べ替え順序を独自に定義したものに変更することができます。
以下の例で使用するIComparer<T>インターフェイスなど、比較処理に関する詳細については以下のページも合わせてご覧ください。
独自の並べ替え順序を定義する
次の例は、並べ替えの順序を独自に定義してSortedList・SortedDictionaryでの並べ替え順をカスタマイズするものです。 大文字小文字の違いを無視し、アルファベット順とは逆順(Z→Aの順)になるようにソートするIComparer<string>を実装したクラスCaseInsensitiveReverseStringComparerを作成し、それをSortedList・SortedDictionaryのコンストラクタに指定することで独自に定義した並べ替え順序となるようにしています。
using System;
using System.Collections.Generic;
// 大文字小文字の違いを無視し、アルファベット順とは逆順にソートするためのIComparer
class CaseInsensitiveReverseStringComparer : IComparer<string> {
public int Compare(string x, string y)
{
// StringComparer.CurrentCultureIgnoreCase.Compareの戻り値の符号を反転して逆順となるような結果を返す
return -1 * StringComparer.CurrentCultureIgnoreCase.Compare(x, y);
}
}
class Sample {
static void Main()
{
// 独自に定義した並べ替え順序を実装するIComparerを指定してSortedListを作成
SortedList<string, int> list = new SortedList<string, int>(new CaseInsensitiveReverseStringComparer());
list["Bob"] = 1;
list["Alice"] = 2;
list["Charlie"] = 3;
list["aLiCe"] = 16;
list["BOB"] = 72;
Console.WriteLine("[SortedList]");
foreach (KeyValuePair<string, int> pair in list) {
Console.WriteLine("{0,-8} => {1}", pair.Key, pair.Value);
}
// 独自に定義した並べ替え順序を実装するIComparerを指定してSortedDictionaryを作成
SortedDictionary<string, int> dict = new SortedDictionary<string, int>(new CaseInsensitiveReverseStringComparer());
dict["Bob"] = 1;
dict["Alice"] = 2;
dict["Charlie"] = 3;
dict["aLiCe"] = 16;
dict["BOB"] = 72;
Console.WriteLine("[SortedDictionary]");
foreach (KeyValuePair<string, int> pair in dict) {
Console.WriteLine("{0,-8} => {1}", pair.Key, pair.Value);
}
}
}
Imports System
Imports System.Collections.Generic
' 大文字小文字の違いを無視し、アルファベット順とは逆順にソートするためのIComparer
Class CaseInsensitiveReverseStringComparer
Implements IComparer(Of String)
Public Function Compare(ByVal x As String, ByVal y As String) As Integer Implements IComparer(Of String).Compare
' StringComparer.CurrentCultureIgnoreCase.Compareの戻り値の符号を反転して逆順となるような結果を返す
Return -1 * StringComparer.CurrentCultureIgnoreCase.Compare(x, y)
End Function
End Class
Class Sample
Shared Sub Main()
' 独自に定義した並べ替え順序を実装するIComparerを指定してSortedListを作成
Dim list As New SortedList(Of String, Integer)(New CaseInsensitiveReverseStringComparer())
list("Bob") = 1
list("Alice") = 2
list("Charlie") = 3
list("aLiCe") = 16
list("BOB") = 72
Console.WriteLine("[SortedList]")
For Each pair As KeyValuePair(Of String, Integer) In list
Console.WriteLine("{0,-8} => {1}", pair.Key, pair.Value)
Next
' 独自に定義した並べ替え順序を実装するIComparerを指定してSortedDictionaryを作成
Dim dict As New SortedDictionary(Of String, Integer)(New CaseInsensitiveReverseStringComparer())
dict("Bob") = 1
dict("Alice") = 2
dict("Charlie") = 3
dict("aLiCe") = 16
dict("BOB") = 72
Console.WriteLine("[SortedDictionary]")
For Each pair As KeyValuePair(Of String, Integer) In dict
Console.WriteLine("{0,-8} => {1}", pair.Key, pair.Value)
Next
End Sub
End Class
[SortedList] Charlie => 3 BOB => 72 aLiCe => 16 [SortedDictionary] Charlie => 3 Bob => 72 Alice => 16
実行結果からもわかるように、大文字小文字の違いがあっても同一のキーとして扱われるようになるため、値は上書きされるようになります。
降順・逆順にする
SortedList・SortedDictionaryにはReverseメソッドが用意されていないため、コレクションの内容を昇順から降順に並べ替え順序を変えることはできません。 並べ替え順序を変えるには新たに別のインスタンスを作成する必要があります。
次の例では、既存のSortedListのコピーを作成し、内容は同じで並べ替え順序だけを逆にしたインスタンスを作成することにより、逆順にしたSortedListを得ています。 新しいSortedListのインスタンスを作成する際、コンストラクタに既存のSortedListを指定することで同一の内容を持つインスタンスを作成します。 同時に、元のIComparer<T>とは逆の順序に並べ替えるようにしたIComparer<T>をコンストラクタに指定することで逆順に並べ替えるようにしています。
この例で紹介する方法では、ComparerプロパティからIComparer<T>を取得することにより、個別に並べ替え順序を定義することなく単に並べ替え順序を逆にしています。 そのため、キーの型に関わらずどのようなSortedListでも逆順にすることができます。
using System;
using System.Collections.Generic;
// 指定されたIComparer<T>と逆の順序に並べ替えるIComparer<T>の実装
class ReverseComparer<T> : IComparer<T> {
private IComparer<T> comparer;
public ReverseComparer(IComparer<T> comparer)
{
this.comparer = comparer;
}
public int Compare(T x, T y)
{
// 指定する引数の順序を逆にすることで、元になったIComparer<T>とは逆の結果を返す
return comparer.Compare(y, x);
}
}
class Sample {
// 内容はそのままで並べ替え順序を逆にしたSortedListを作成するメソッド
static SortedList<TKey, TValue> CreateReversed<TKey, TValue>(SortedList<TKey, TValue> source)
{
// コレクションの内容はsourceと同じもの、並べ替え順序はsource.Comparerで
// 定義されているものとは逆となるようなインスタンスを返す
return new SortedList<TKey, TValue>(source, new ReverseComparer<TKey>(source.Comparer));
}
static void Main()
{
// キーがstringのSortedList
SortedList<string, int> list1 = new SortedList<string, int>();
list1["Bob"] = 1;
list1["Alice"] = 2;
list1["Charlie"] = 3;
// 逆順にしたものを作成し、内容を表示
foreach (KeyValuePair<string, int> pair in CreateReversed(list1)) {
Console.WriteLine("{0,-8} => {1}", pair.Key, pair.Value);
}
Console.WriteLine();
// キーがintのSortedList
SortedList<int, string> list2 = new SortedList<int, string>();
list2[2] = "Alice";
list2[1] = "Bob";
list2[3] = "Charlie";
// 逆順にしたものを作成し、内容を表示
foreach (KeyValuePair<int, string> pair in CreateReversed(list2)) {
Console.WriteLine("{0} => {1}", pair.Key, pair.Value);
}
}
}
Imports System
Imports System.Collections.Generic
' 指定されたIComparer<T>と逆の順序に並べ替えるIComparer<T>の実装
Class ReverseComparer(Of T)
Implements IComparer(Of T)
Private comparer As IComparer(Of T)
Public Sub New(ByVal comparer As IComparer(Of T))
Me.comparer = comparer
End SUb
Public Function Compare(ByVal x As T, ByVal y As T) As Integer Implements IComparer(Of T).Compare
' 指定する引数の順序を逆にすることで、元になったIComparer<T>とは逆の結果を返す
Return comparer.Compare(y, x)
End Function
End Class
Class Sample
' 内容はそのままで並べ替え順序を逆にしたSortedListを作成するメソッド
Shared Function CreateReversed(Of TKey, TValue)(ByVal source As SortedList(Of TKey, TValue)) As SortedList(Of TKey, TValue)
' コレクションの内容はsourceと同じもの、並べ替え順序はsource.Comparerで
' 定義されているものとは逆となるようなインスタンスを返す
Return New SortedList(Of TKey, TValue)(source, New ReverseComparer(Of TKey)(source.Comparer))
End Function
Shared Sub Main()
' キーがstringのSortedList
Dim list1 As New SortedList(Of String, Integer)()
list1("Bob") = 1
list1("Alice") = 2
list1("Charlie") = 3
' 逆順にしたものを作成し、内容を表示
For Each pair As KeyValuePair(Of String, Integer) In CreateReversed(list1)
Console.WriteLine("{0,-8} => {1}", pair.Key, pair.Value)
Next
Console.WriteLine()
' キーがintのSortedList
Dim list2 As New SortedList(Of Integer, String)()
list2(2) = "Alice"
list2(1) = "Bob"
list2(3) = "Charlie"
' 逆順にしたものを作成し、内容を表示
For Each pair As KeyValuePair(Of Integer, String) In CreateReversed(list2)
Console.WriteLine("{0} => {1}", pair.Key, pair.Value)
Next
End Sub
End Class
Charlie => 3 Bob => 1 Alice => 2 3 => Charlie 2 => Alice 1 => Bob
この方法は、SortedDictionaryでも同様に実装することができます。
単に逆順にした状態で列挙できればよいのであれば、LINQのReverseメソッドを使うこともできます。 この場合、新たにIComparer<T>を用意する必要がないため、より単純に実現できます。 この方法もSortedList・SortedDictionaryの両方に適用できます。
using System;
using System.Collections.Generic;
using System.Linq;
class Sample {
static void Main()
{
// キーがstringのSortedList
SortedList<string, int> list1 = new SortedList<string, int>();
list1["Bob"] = 1;
list1["Alice"] = 2;
list1["Charlie"] = 3;
// Reverseメソッドを使ってSortedListを逆順で列挙する
foreach (KeyValuePair<string, int> pair in list1.Reverse()) {
Console.WriteLine("{0,-8} => {1}", pair.Key, pair.Value);
}
Console.WriteLine();
// キーがintのSortedList
SortedList<int, string> list2 = new SortedList<int, string>();
list2[2] = "Alice";
list2[1] = "Bob";
list2[3] = "Charlie";
// Reverseメソッドを使ってSortedListを逆順で列挙する
foreach (KeyValuePair<int, string> pair in list2.Reverse()) {
Console.WriteLine("{0} => {1}", pair.Key, pair.Value);
}
}
}
Imports System
Imports System.Collections.Generic
Imports System.Linq
Class Sample
Shared Sub Main()
' キーがstringのSortedList
Dim list1 As New SortedList(Of String, Integer)()
list1("Bob") = 1
list1("Alice") = 2
list1("Charlie") = 3
' Reverseメソッドを使ってSortedListを逆順で列挙する
For Each pair As KeyValuePair(Of String, Integer) In list1.Reverse()
Console.WriteLine("{0,-8} => {1}", pair.Key, pair.Value)
Next
Console.WriteLine()
' キーがintのSortedList
Dim list2 As New SortedList(Of Integer, String)()
list2(2) = "Alice"
list2(1) = "Bob"
list2(3) = "Charlie"
' Reverseメソッドを使ってSortedListを逆順で列挙する
For Each pair As KeyValuePair(Of Integer, String) In list2.Reverse()
Console.WriteLine("{0} => {1}", pair.Key, pair.Value)
Next
End Sub
End Class
Charlie => 3 Bob => 1 Alice => 2 3 => Charlie 2 => Alice 1 => Bob
また、既存のSortedList・SortedDictionaryを降順にするのではなく、始めから降順に並べ替えるように動作するSortedList・SortedDictionaryを作成したい場合は、先の例のReverseComparerをコンストラクタに指定します。
using System;
using System.Collections.Generic;
// 指定されたIComparer<T>と逆の順序に並べ替えるIComparer<T>の実装
class ReverseComparer<T> : IComparer<T> {
private IComparer<T> comparer;
public ReverseComparer(IComparer<T> comparer)
{
this.comparer = comparer;
}
public int Compare(T x, T y)
{
// 指定する引数の順序を逆にすることで、元になったIComparer<T>とは逆の結果を返す
return comparer.Compare(y, x);
}
}
class Sample {
static void Main()
{
// キーがstringで、降順に並べ替えるSortedListを作成する
IComparer<string> descendingStringComparer = new ReverseComparer<string>(Comparer<string>.Default);
SortedList<string, int> list1 = new SortedList<string, int>(descendingStringComparer);
list1["Bob"] = 1;
list1["Alice"] = 2;
list1["Charlie"] = 3;
// 内容を表示
foreach (KeyValuePair<string, int> pair in list1) {
Console.WriteLine("{0,-8} => {1}", pair.Key, pair.Value);
}
Console.WriteLine();
// キーがintで、降順に並べ替えるSortedListを作成する
IComparer<int> descendingIntComparer = new ReverseComparer<int>(Comparer<int>.Default);
SortedList<int, string> list2 = new SortedList<int, string>(descendingIntComparer);
list2[2] = "Alice";
list2[1] = "Bob";
list2[3] = "Charlie";
// 内容を表示
foreach (KeyValuePair<int, string> pair in list2) {
Console.WriteLine("{0} => {1}", pair.Key, pair.Value);
}
}
}
Imports System
Imports System.Collections.Generic
' 指定されたIComparer<T>と逆の順序に並べ替えるIComparer<T>の実装
Class ReverseComparer(Of T)
Implements IComparer(Of T)
Private comparer As IComparer(Of T)
Public Sub New(ByVal comparer As IComparer(Of T))
Me.comparer = comparer
End SUb
Public Function Compare(ByVal x As T, ByVal y As T) As Integer Implements IComparer(Of T).Compare
' 指定する引数の順序を逆にすることで、元になったIComparer<T>とは逆の結果を返す
Return comparer.Compare(y, x)
End Function
End Class
Class Sample
Shared Sub Main()
' キーがStringで、降順に並べ替えるSortedListを作成する
Dim descendingStringComparer As New ReverseComparer(Of String)(Comparer(Of String).Default)
Dim list1 As New SortedList(Of String, Integer)(descendingStringComparer)
list1("Bob") = 1
list1("Alice") = 2
list1("Charlie") = 3
' 内容を表示
For Each pair As KeyValuePair(Of String, Integer) In list1
Console.WriteLine("{0,-8} => {1}", pair.Key, pair.Value)
Next
Console.WriteLine()
' キーがIntegerで、降順に並べ替えるSortedListを作成する
Dim descendingIntComparer As New ReverseComparer(Of Integer)(Comparer(Of Integer).Default)
Dim list2 As New SortedList(Of Integer, String)(descendingIntComparer)
list2(2) = "Alice"
list2(1) = "Bob"
list2(3) = "Charlie"
' 内容を表示
For Each pair As KeyValuePair(Of Integer, String) In list2
Console.WriteLine("{0} => {1}", pair.Key, pair.Value)
Next
End Sub
End Class
Charlie => 3 Bob => 1 Alice => 2 3 => Charlie 2 => Alice 1 => Bob
キーに独自型を使用する
構造体やクラスなど、独自に定義した型をSortedList・SortedDictionaryのキーとする場合は、その型の比較を行うIComparer<T>を用意しなければ並べ替えを行うことができません。 次の例は、構造体をキーとしたSortedListを作成・使用する例です。 この方法はSortedListだけでなくSortedDictionaryの場合にも適用できます。
using System;
using System.Collections.Generic;
// SortedListのキーとして使用する構造体
struct Account {
public string Name;
public int ID;
public Account(string name, int id)
{
Name = name;
ID = id;
}
}
// Account構造体のNameフィールドで並べ替えを行うIComparer<T>
class AccountNameComparer : IComparer<Account> {
public int Compare(Account x, Account y)
{
return string.Compare(x.Name, y.Name);
}
}
// Account構造体のIDフィールドで並べ替えを行うIComparer<T>
class AccountIDComparer : IComparer<Account> {
public int Compare(Account x, Account y)
{
return x.ID - y.ID;
}
}
class Sample {
static void Main()
{
// キーにAccount構造体を使用し、Nameフィールドに従って並べ替えるSortedList
SortedList<Account, string> list1 = new SortedList<Account, string>(new AccountNameComparer());
list1[new Account("Bob", 1)] = "bob@example.com";
list1[new Account("Charlie", 3)] = "charlie@example.net";
list1[new Account("Alice", 2)] = "alice@mail.example.net";
// 内容を表示
foreach (KeyValuePair<Account, string> pair in list1) {
Console.WriteLine("{0}:{1,-8} => {2}", pair.Key.ID, pair.Key.Name, pair.Value);
}
Console.WriteLine();
// キーにAccount構造体を使用し、IDフィールドに従って並べ替えるSortedList
SortedList<Account, string> list2 = new SortedList<Account, string>(new AccountIDComparer());
list2[new Account("Bob", 1)] = "bob@example.com";
list2[new Account("Charlie", 3)] = "charlie@example.net";
list2[new Account("Alice", 2)] = "alice@mail.example.net";
// 内容を表示
foreach (KeyValuePair<Account, string> pair in list2) {
Console.WriteLine("{0}:{1,-8} => {2}", pair.Key.ID, pair.Key.Name, pair.Value);
}
}
}
Imports System
Imports System.Collections.Generic
' SortedListのキーとして使用する構造体
Structure Account
Public Name As String
Public ID As Integer
Public Sub New(ByVal name As String, ByVal id As Integer)
Me.Name = name
Me.ID = id
End Sub
End Structure
' Account構造体のNameフィールドで並べ替えを行うIComparer(Of T)
Class AccountNameComparer
Implements IComparer(Of Account)
Public Function Compare(ByVal x As Account, ByVal y As Account) As Integer Implements IComparer(Of Account).Compare
Return String.Compare(x.Name, y.Name)
End Function
End Class
' Account構造体のIDフィールドで並べ替えを行うIComparer(Of T)
Class AccountIDComparer
Implements IComparer(Of Account)
Public Function Compare(ByVal x As Account, ByVal y As Account) As Integer Implements IComparer(Of Account).Compare
Return x.ID - y.ID
End Function
End Class
Class Sample
Shared Sub Main()
' キーにAccount構造体を使用し、Nameフィールドに従って並べ替えるSortedList
Dim list1 As New SortedList(Of Account, String)(New AccountNameComparer())
list1(New Account("Bob", 1)) = "bob@example.com"
list1(New Account("Charlie", 3)) = "charlie@example.net"
list1(New Account("Alice", 2)) = "alice@mail.example.net"
' 内容を表示
For Each pair As KeyValuePair(Of Account, String) In list1
Console.WriteLine("{0}:{1,-8} => {2}", pair.Key.ID, pair.Key.Name, pair.Value)
Next
Console.WriteLine()
' キーにAccount構造体を使用し、IDフィールドに従って並べ替えるSortedList
Dim list2 As New SortedList(Of Account, String)(New AccountIDComparer())
list2(New Account("Bob", 1)) = "bob@example.com"
list2(New Account("Charlie", 3)) = "charlie@example.net"
list2(New Account("Alice", 2)) = "alice@mail.example.net"
' 内容を表示
For Each pair As KeyValuePair(Of Account, String) In list2
Console.WriteLine("{0}:{1,-8} => {2}", pair.Key.ID, pair.Key.Name, pair.Value)
Next
End Sub
End Class
2:Alice => alice@mail.example.net 1:Bob => bob@example.com 3:Charlie => charlie@example.net 1:Bob => bob@example.com 2:Alice => alice@mail.example.net 3:Charlie => charlie@example.net
独自型のIComparer<T>を実装する方法の詳細については複合型のソート・複数キーでのソートや大小関係の定義と比較を参照してください。
パフォーマンスの違い
SortedListクラスとSortedDictionaryクラスでは、内部で使用されるデータ構造の違いから使用するメモリの量と挿入・削除の速度にも違いがあらわれます。 Sorted コレクション型によると、両者の違いは次のようになっています。
相違点 | SortedList | SortedDictionary |
---|---|---|
取得操作の速度 | O(log n) | |
挿入操作・削除操作の速度 | 一般にO(n) | 常にO(log n) |
使用するメモリ量 | 比較して少ない | 比較して多い |
SortedListでは、新しい要素が末尾に挿入される場合(挿入の際に並べ替えが発生せず、かつ挿入により内部コレクションのサイズが変わらない場合)、挿入操作の速度は O(1) となります。
以下は、互いに重複しないシャッフルされたキーを使って要素を追加した場合の速度を比較した結果の一例です。
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Security.Cryptography;
class Sample {
// 0からcountまでの数値をランダムな順番で返すメソッド
static IEnumerable<int> GetShuffledNumbers(int count)
{
var rng = RandomNumberGenerator.Create();
var bytes = new byte[4];
return Enumerable.Range(0, count).OrderBy(i => {
rng.GetBytes(bytes);
return BitConverter.ToInt32(bytes, 0);
});
}
static void Main()
{
#if DEBUG
foreach (var key in GetShuffledNumbers(50)) {
Console.Write("{0}, ", key);
}
Console.WriteLine();
return;
#endif
const int keyCount = 100 * 1000;
const int repeatCount = 3;
for (var repeat = 0; repeat < repeatCount; repeat++) {
var keys = GetShuffledNumbers(keyCount).ToArray();
Console.WriteLine("[{0}]", repeat);
var list = new SortedList<int, int>();
var sw1 = Stopwatch.StartNew();
foreach (var key in keys) {
list.Add(key, key);
}
sw1.Stop();
Console.WriteLine("{0,-20}(Count = {1}): {2}", "SortedList", list.Count, sw1.Elapsed);
var dict = new SortedDictionary<int, int>();
var sw2 = Stopwatch.StartNew();
foreach (var key in keys) {
dict.Add(key, key);
}
sw2.Stop();
Console.WriteLine("{0,-20}(Count = {1}): {2}", "SortedDictionary", dict.Count, sw2.Elapsed);
Console.WriteLine("{0:P2}", sw1.ElapsedTicks / (double)sw2.ElapsedTicks);
}
}
}
[0] SortedList (Count = 100000): 00:00:03.6776776 SortedDictionary (Count = 100000): 00:00:00.0915454 4,017.33% [1] SortedList (Count = 100000): 00:00:03.7265242 SortedDictionary (Count = 100000): 00:00:00.0542817 6,865.15% [2] SortedList (Count = 100000): 00:00:04.1011721 SortedDictionary (Count = 100000): 00:00:00.0748488 5,479.27%
このように、同じ挿入の操作でも速度にかなり大きな差が出ていることが分かると思います。 一方、上記の例のGetShuffledNumbersを次のように変更し、並べ替えが行われないようキーがソートされた状態にすると結果は反転します。
static IEnumerable<int> GetShuffledNumbers(int count)
{
// ランダムな順番ではなく、ソートが不要な順番で返すようにする
return Enumerable.Range(0, count);
}
[0] SortedList (Count = 100000): 00:00:00.0222451 SortedDictionary (Count = 100000): 00:00:00.0748501 29.72% [1] SortedList (Count = 100000): 00:00:00.0204976 SortedDictionary (Count = 100000): 00:00:00.0529541 38.71% [2] SortedList (Count = 100000): 00:00:00.0179380 SortedDictionary (Count = 100000): 00:00:00.0554350 32.36%
これは、SortedDictionaryでは挿入操作は常にO(log n)であるのに対し、SortedListではキーがソート済みの順で要素が追加されていくために新しい要素は末尾に追加するだけでよく、挿入操作がO(1)となるためです。