2010-10-10T06:04:50の更新内容

programming/tips/shuffle_array/index.wiki.txt

current previous
1,158 1,11
~
${smdncms:title,配列・コレクションのシャッフル}
${smdncms:title,配列のシャッフル}
~
${smdncms:keywords,VB.NET,C#,配列,コレクション,ランダム,シャッフル}
${smdncms:keywords,VB.NET,C#,配列,ランダム,シャッフル}
 
${smdncms:tags,algo,lang/vb,lang/c#}
${smdncms:tags,algo,lang/vb,lang/c#}
 

        

        
~
配列・コレクションをシャッフルする方法について。
配列のシャッフルを行うためのメソッド。 使いやすいように拡張メソッドとして呼び出せるようにしてある。 オリジナルの配列には変更を加えず、シャッフルした配列を戻り値として返す。
 

        

        
 
#googleadunit
#googleadunit
 

        

        
+
*配列・コレクション・IEnumerable<T>のシャッフル
+
&msdn(netfx,method,System.Linq.Enumerable.OrderBy){Enumerable.OrderByメソッド};を使って任意のIEnumerable<T>をシャッフルするためのメソッドの例。 OrderByメソッドに対してランダムなキーを与えることで、''ランダムな順序''に並べ替える。
+

          
+
この例では、ランダムなキーの生成に&msdn(netfx,type,System.Security.Cryptography.RandomNumberGenerator){RandomNumberGeneratorクラス};を使用しているが、Randomクラスを用いても同じように実装できる。 また、使いやすいように拡張メソッドとして呼び出せるようにしてある。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections.Generic;
+
using System.Linq;
+
using System.Security.Cryptography;
+

          
+
public static class IEnumerableExtensions {
+
  public static IOrderedEnumerable<TSource> Shuffle<TSource>(this IEnumerable<TSource> source)
+
  {
+
    return Shuffle(source, RandomNumberGenerator.Create());
+
  }
+

          
+
  public static IOrderedEnumerable<TSource> Shuffle<TSource>(this IEnumerable<TSource> source, RandomNumberGenerator rng)
+
  {
+
    if (source == null)
+
      throw new ArgumentNullException("source");
+

          
+
    var bytes = new byte[4];
+

          
+
    return source.OrderBy(delegate(TSource e) {
+
      rng.GetBytes(bytes);
+

          
+
      return BitConverter.ToInt32(bytes, 0);
+
    });
+

          
+
    /* Randomクラスを使う場合
+
    var random = new Random();
+

          
+
    return source.OrderBy(delegate(TSource e) {
+
      return random.Next();
+
    });
+
    */
+
  }
+
}
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    var col1 = new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+

          
+
    Print(col1);
+
    Print(col1.Shuffle());
+

          
+
    var col2 = new Queue<string>(new[] {"foo", "bar", "baz"});
+

          
+
    Print(col2);
+
    Print(col2.Shuffle());
+

          
+
    var col3 = new List<int>();
+

          
+
    Print(col3);
+
    Print(col3.Shuffle());
+
  }
+

          
+
  private static void Print<T>(IEnumerable<T> source)
+
  {
+
    foreach (var val in source) {
+
      Console.Write(val);
+
      Console.Write(" ");
+
    }
+

          
+
    Console.WriteLine();
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections.Generic
+
Imports System.Linq
+
Imports System.Security.Cryptography
+

          
+
Module IEnumerableExtensions
+
  <System.Runtime.CompilerServices.Extension()> _
+
  Public Function Shuffle(Of TSource)(ByVal source As IEnumerable(Of TSource)) As IOrderedEnumerable(Of TSource)
+
    Return Shuffle(source, RandomNumberGenerator.Create())
+
  End Function
+

          
+
  Public Function Shuffle(Of TSource)(ByVal source As IEnumerable(Of TSource), ByVal rng As RandomNumberGenerator) As IOrderedEnumerable(Of TSource)
+
    If source Is Nothing Then Throw New ArgumentNullException("source")
+

          
+
    Dim bytes(3) As Byte
+

          
+
    Return source.OrderBy(Function(e)
+
      rng.GetBytes(bytes)
+

          
+
      Return BitConverter.ToInt32(bytes, 0)
+
    End Function)
+

          
+
    ' Randomクラスを使う場合
+
    'Dim random As New Random()
+
    '
+
    'Return source.OrderBy(Function(e)
+
    '  Return random.Next()
+
    'End Function)
+
  End Function
+
End Module
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Dim arr1() As Integer = New Integer() {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
+

          
+
    Print(arr1)
+
    Print(arr1.Shuffle())
+

          
+
    Dim arr2 As New Queue(Of String)(New String() {"foo", "bar", "baz"})
+

          
+
    Print(arr2)
+
    Print(arr2.Shuffle())
+

          
+
    Dim arr3 As New List(Of Integer)()
+

          
+
    Print(arr3)
+
    Print(arr3.Shuffle())
+
  End Sub
+

          
+
  Private Shared Sub Print(Of T)(ByVal source As IEnumerable(Of T))
+
    For Each val As T In source
+
      Console.Write(val)
+
      Console.Write(" ")
+
    Next
+

          
+
    Console.WriteLine()
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果の例){{
+
0 1 2 3 4 5 6 7 8 9 
+
8 9 3 0 4 6 1 2 5 7 
+
foo bar baz 
+
baz bar foo 
+

          
+

          
+
Press any key to continue
+
}}
+

          
+
*配列のシャッフル
+
配列のシャッフルを行うためのメソッドの例。 使いやすいように拡張メソッドとして呼び出せるようにしてある。 オリジナルの配列には変更を加えず、シャッフルした配列を戻り値として返す。
+

          
 
#tabpage(C#)
#tabpage(C#)
 
#code(cs){{
#code(cs){{
 
public static class ArrayExtensions {
public static class ArrayExtensions {
277,7 130,9
 
}}
}}
 
#tabpage-end
#tabpage-end
 

        

        
~
#prompt(実行結果の例){{
実行結果。
-

          
-
#prompt(実行結果){{
 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
 
4 8 5 9 3 0 2 6 1 7 
4 8 5 9 3 0 2 6 1 7 
 
foo bar baz 
foo bar baz 

programming/netfx2/overview/collection/index.wiki.txt

current previous
1,6946 1,549
~
${smdncms:title,コレクション(System.Collections)}
${smdncms:title,コレクション(System.Collection)}
+
${smdncms:keywords,Collections,Generic,List,ArrayList,Dictionary,IList,Queue,Stack}
 
${smdncms:meta,toc-amazonlivelink-keyword,books-jp,.net framework}
${smdncms:meta,toc-amazonlivelink-keyword,books-jp,.net framework}
~

          
.NET FrameworkのSystem.Collection名前空間には様々な機能を持った便利なクラスが複数存在します。 これらはコレクションと呼ばれ、一般的に使う配列の様に一つのコレクションオブジェクトが複数のオブジェクトを保持する一方、配列とは異なり、ソートや動的な領域確保など配列ではなしえない機能を持っています。 ここではその便利なコレクションクラスのいくつかを見ていくことにします。
+
.NET FrameworkのSystem.Collections名前空間には様々な機能を持った便利なクラスが複数存在します。 これらはコレクションと呼ばれ、一般的に使う配列の様に一つのコレクションオブジェクトが複数のオブジェクトを保持する一方、配列とは異なり、ソートや動的な領域確保など配列にはない機能も持っています。 また、キューやスタック、リスト、集合などのデータ構造もコレクションとして用意されています。
+

          
+
ここではそのコレクションクラスについて解説します なお、以下のページでも列挙やソートなどコレクションの操作に関連することについて解説しています。
+

          
+
-関連するページ
+
--[[programming/netfx2/overview/enumeration]]
+
--[[programming/netfx2/overview/sort_comparison]]
+
--[[programming/tips/shuffle_array]]
+

          
+
注意: この文章ではLINQおよび&msdn(netfx,type,System.Linq.Enumerable){Enumerableクラス};などで提供される拡張メソッド、マルチスレッドでの使用については踏み込みません。 必要に応じて他のドキュメントを参照してください。
+

          
 
#googleadunit
#googleadunit
 

        

        
~
----
*ArrayList
~

          
ArrayListクラスは配列に非常によく似ています。 しかし、配列とは異なり、動的に配列の大きさを増減できることがArrayListの特徴であります。 次のコードは、ArrayListを使った一般的なソースコードです。
+
*コレクションの種類と特徴
+
個々のコレクションクラスについて詳しく見ていく前に、.NET Frameworkで用意されているコレクションのいくつかと特徴をざっと見ていきます。 .NET Frameworkでは、以下の名前空間にコレクションクラスと関連するインターフェイスが配置されています。
+

          
+
:&msdn(netfx,ns,System.Collections){System.Collections名前空間};|基本的な非ジェネリックなコレクションクラスと関連するインターフェイス
+
:&msdn(netfx,ns,System.Collections.Generic){System.Collections.Generic名前空間};|ジェネリックコレクションクラスと関連するインターフェイス
+
:&msdn(netfx,ns,System.Collections.Concurrent){System.Collections.Concurrent名前空間};|マルチスレッドでの操作を目的としたスレッドセーフなジェネリックコレクションクラスと関連するインターフェイス
+
:&msdn(netfx,ns,System.Collections.ObjectModel){System.Collections.ObjectModel名前空間};|独自にジェネリックコレクションクラスを実装するための基本クラス
+
:&msdn(netfx,ns,System.Collections.Specialized){System.Collections.Specialized名前空間};|特定用途に用いられるタイプセーフな非ジェネリックコレクションクラス
+

          
+
これらの名前空間に配置されているコレクションクラスの種類を大まかに分けると次の4つになります。
+
:コレクション|単純な要素の集まり
+
&msdn(netfx,id,92t2ye13){ICollection<T>};や&msdn(netfx,type,System.Collections.ICollection){ICollection};を実装するクラス
+
:リスト|コレクションの機能に加え、要素の入れ替えやインデックスによるアクセスができるコレクション
+
&msdn(netfx,id,5y536ey6){IList<T>};や&msdn(netfx,type,System.Collections.IList){IList};を実装するクラス
+
:ディクショナリ|キーによる要素へのアクセスが出来るコレクション
+
&msdn(netfx,id,s4ys34ea){IDictionary<TKey, TValue>};や&msdn(netfx,type,System.Collections.IDictionary){IDictionary};を実装するクラス
+
:セット(集合)|集合の概念を表すコレクション
+
&msdn(netfx,id,dd412081){ISet<T>};(.NET Framework 4以降)を実装するクラス
+

          
+
上記のインターフェイスはすべて&msdn(netfx,id,9eekhta0){IEnumerable<T>};および&msdn(netfx,type,System.Collections.IEnumerable){IEnumerable};を継承しているため、結果としてすべてのコレクションクラスは列挙操作が可能になっています。
+

          
+
個々のコレクションクラスが実装するインターフェイスを見ることで、そのコレクションクラスの大まかな特徴が分かります。 以下の表はコレクションクラスの特徴と実装するインターフェイスを抜粋して表にまとめたものです(個々のクラスの解説にもリンクしています)。 比較のため、配列(Array)も含めています。 あわせて、要素の取得・設定の操作と、挿入・削除の操作のオーダーを[[ランダウの記号:http://ja.wikipedia.org/wiki/%E3%83%A9%E3%83%B3%E3%83%80%E3%82%A6%E3%81%AE%E8%A8%98%E5%8F%B7]]を用いて併記しています。 表中のnはコレクション内の要素数を表します。
+

          
+
|*コレクション、リストのクラスと特徴
+
|~クラス|~データ構造|~インデックスによるアクセス|~要素の取得・設定|~要素の挿入・削除|~実装するインターフェイス|h
+
|~Array|固定長配列|できる|O(1)|-|IList<T>, ICollection<T>, IList, ICollection|
+
|~[[ArrayList>#ArrayList]]|可変長配列|できる|O(1)|O(n)&sup{*1};|IList, ICollection|
+
|~[[List<T>>#Generic.List]]|可変長配列|できる|O(1)|O(n)&sup{*1};|IList<T>, IList, ICollection<T>, ICollection|
+
|~[[Collection<T>>#ObjectModel.Collection]]|可変長配列|できる|O(1)|O(n)&sup{*1};|IList<T>, IList, ICollection<T>, ICollection|
+
|~[[LinkedList<T>>#Generic.LinkedList]]|双方向連結リスト|できない|O(1)&sup{*2};|O(1)|ICollection<T>, ICollection|
+
|~[[Queue>#Queue]]|キュー|できない|O(1)&sup{*3};|O(n)&sup{*1};|ICollection|
+
|~[[Queue<T>>#Generic.Queue]]|キュー|できない|O(1)&sup{*3};|O(n)&sup{*1};|ICollection|
+
|~[[Stack>#Stack]]|スタック|できない|O(1)&sup{*3};|O(n)&sup{*1};|ICollection|
+
|~[[Stack<T>>#Generic.Stack]]|スタック|できない|O(1)&sup{*3};|O(n)&sup{*1};|ICollection|
+

          
+
:*1|容量の拡張が不要で、かつ末尾への追加となる場合はO(1)となる。
+
:*2|取得・設定しようとするノードの位置が既知の場合。 ノードの検索はO(n)となる。
+
:*3|Peek, Dequeue, Popなどの操作による取得の場合。 設定は出来ない。
+

          
+
|*ディクショナリのクラスと特徴
+
|~クラス|~インデックスによるアクセス|~要素のソート|~要素のキー|~要素の取得・設定|~要素の挿入・削除|~実装するインターフェイス|h
+
|~[[Hashtable>#Hashtable]]|できない|されない|独立した値|O(1)|O(1)&sup{*2};|IDictionary, ICollection|
+
|~[[Dictionary<TKey, TValue>>#Generic.Dictionary]]|できない|されない|独立した値|ほぼO(1)|ほぼO(1)&sup{*2};|IDictionary<TKey, TValue>, IDictionary, ICollection<KeyValuePair<TKey, TValue>>, ICollection|
+
|~[[SortedList>#SortedList]]|できる|される|独立した値|O(log n)&sup{*1};|O(n)&sup{*3};|IDictionary, ICollection|
+
|~[[SortedList<TKey, TValue>>#Generic.SortedListSortedDictionary]]|できる|される|独立した値|O(log n)&sup{*1};|O(n)&sup{*3};|IDictionary<TKey, TValue>, IDictionary, ICollection<KeyValuePair<TKey, TValue>>, ICollection|
+
|~[[SortedDictionary<TKey, TValue>>#Generic.SortedListSortedDictionary]]|できない|される|独立した値|O(log n)|O(log n)|IDictionary<TKey, TValue>, IDictionary, ICollection<KeyValuePair<TKey, TValue>>, ICollection|
+
|~[[KeyedCollection<TKey, TItem>>#ObjectModel.KeyedCollection]]|できる|されない|要素自身から取得|O(1)|O(n)&sup{*4};|IList<TItem>, IList, ICollection<TItem>, ICollection|
+

          
+
:*1|存在しないキーの要素を設定する場合はO(n)となる。
+
:*2|挿入により容量が拡張される場合はO(n)となる。
+
:*3|末尾への追加となる場合はO(log n)となる。
+
:*4|末尾への追加となる場合はO(1)となる。
+

          
+
|*セットのクラスと特徴
+
|~クラス|~インデックスによるアクセス|~要素のソート|~要素の挿入・削除|~実装するインターフェイス|h
+
|~[[HashSet<T>>#Generic.HashSetSortedSet]]|できない|されない|O(1)&sup{*1};|ISet<T>, ICollection<T>|
+
|~[[SortedSet<T>>#Generic.HashSetSortedSet]]|できない|される|O(1)&sup{*1};|ISet<T>, ICollection<T>, ICollection|
+

          
+
:*1|挿入により容量が拡張される場合はO(n)となる。
+

          
+
*&aname(NonGenericCollections){非ジェネリックコレクション (System.Collections)};
+
ここでは&msdn(netfx,ns,System.Collections){System.Collections名前空間};にある、非ジェネリックなコレクションを見ていきます。 非ジェネリックコレクションよりもジェネリックコレクションを使うことが多いですが、どちらも機能と動作の点で共通する部分が多いため、まずはジェネリックコレクションについて触れる前に配列との違いや各コレクションクラスの動作や基本的な機能を理解するために、非ジェネリックコレクションクラスを用いて説明していきます。
+

          
+
**&aname(ArrayList){ArrayList};
+
&msdn(netfx,type,System.Collections.ArrayList){System.Collections.ArrayListクラス};は配列に非常によく似たクラスですが、要素の数が固定である配列とは異なり動的に要素の数を増減できるという特徴を持っています。 (ArrayListクラスに相当するジェネリックなコレクションクラスは、[[System.Collections.Generic.List>#Generic.List]]クラスです)
 

        

        
+
***基本的な操作
+
早速、ArrayListを使った基本的な操作について見ていきます。 次のコードは、ArrayListクラスを使った例です。
+

          
+
#tabpage(C#)
 
#code(cs){{
#code(cs){{
 
using System;
using System;
 
using System.Collections;
using System.Collections;
 

        

        
~
class Sample
namespace Collection
 
{
{
~
  static void Main()
    class Collection
~
  {
    {
~
    ArrayList arr = new ArrayList();
        [STAThread]
~

          
        static void Main(string[] args)
~
    // 要素の追加
        {
~
    arr.Add(0);
            // ArrayList のインスタンスを作成
~
    arr.Add(1);
            ArrayList arr = new ArrayList();
+
    arr.Add(2);
+

          
+
    Print(arr);
 

        

        
~
    // 複数の要素の追加
            // アイテムを追加
~
    arr.AddRange(new int[] {3, 4, 5, 6});
            arr.Add( 2 );
-
            arr.Add( 8 );
-
            arr.Add( 5 );
-
            arr.Add( 0 );
-
            arr.Add( 4 );
-
            arr.Add( 9 );
-
            arr.Add( 7 );
-
            arr.Add( 3 );
-
            arr.Add( 6 );
-
            arr.Add( 1 );
 

        

        
~
    Print(arr);
            // アイテムを削除
-
            arr.Remove( 1 );
-
            arr.Remove( 4 );
-
            arr.Remove( 6 );
-
            arr.Remove( 9 );
 

        

        
~
    // 要素の削除
            // 特定の位置にあるアイテムを削除
~
    arr.Remove(3);
            arr.RemoveAt( 1 );
+
    arr.Remove(6);
 

        

        
~
    Print(arr);
            // 列挙
-
            EnumerateArrayList( arr );
 

        

        
~
    // 特定の位置にある要素を削除
            // ソート
~
    arr.RemoveAt(0);
            arr.Sort();
 

        

        
~
    Print(arr);
            // 再び列挙
-
            EnumerateArrayList( arr );
 

        

        
~
    // 特定の位置にある要素を変更
            // 順番を反転
~
    arr[2] = 7;
            arr.Reverse();
 

        

        
~
    Print(arr);
            // 再び列挙
-
            EnumerateArrayList( arr );
 

        

        
~
    // 特定の位置に要素を挿入
        }
+
    arr.Insert(2, 3);
 

        

        
~
    Print(arr);
        // ArrayListの値を列挙
-
        public static void EnumerateArrayList( ArrayList arr )
-
        {
-
            for ( int i = 0; i < arr.Count; i++ )
-
            {
-
                Console.Write( arr[i].ToString() + ", " );
-
            }
 

        

        
~
    // ArrayListの内容をソート
            // 改行
~
    arr.Sort();
            Console.Write( Console.Out.NewLine );
-
        }
 

        

        
+
    Print(arr);
+

          
+
    // ArrayListの内容を反転
+
    arr.Reverse();
+

          
+
    Print(arr);
+
  }
+

          
+
  static void Print(ArrayList arr)
+
  {
+
    for (int i = 0; i < arr.Count; i++)
+
    {
+
      Console.Write("{0}, ", arr[i]);
 
    }
    }
+

          
+
    Console.WriteLine();
+
  }
 
}
}
 
}}
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim arr As New ArrayList()
+

          
+
    ' 要素の追加
+
    arr.Add(0)
+
    arr.Add(1)
+
    arr.Add(2)
+

          
+
    Print(arr)
+

          
+
    ' 複数の要素の追加
+
    arr.AddRange(New Integer() {3, 4, 5, 6})
+

          
+
    Print(arr)
+

          
+
    ' 要素の削除
+
    arr.Remove(3)
+
    arr.Remove(6)
+

          
+
    Print(arr)
+

          
+
    ' 特定の位置にある要素を削除
+
    arr.RemoveAt(0)
+

          
+
    Print(arr)
+

          
+
    ' 特定の位置にある要素を変更
+
    arr(2) = 7
+

          
+
    Print(arr)
+

          
+
    ' 特定の位置に要素を挿入
+
    arr.Insert(2, 3)
+

          
+
    Print(arr)
+

          
+
    ' ArrayListの内容をソート
+
    arr.Sort()
+

          
+
    Print(arr)
+

          
+
    ' ArrayListの内容を反転
+
    arr.Reverse()
+

          
+
    Print(arr)
+
  End Sub
+

          
+
  Shared Sub Print(ByVal arr As ArrayList)
+
    For i As Integer = 0 To arr.Count - 1
+
      Console.Write("{0}, ", arr(i))
+
    Next
+

          
+
    Console.WriteLine()
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
 

        

        
~
#prompt{{
#prompt(実行結果){{
~
0, 1, 2, 
2, 5, 0, 7, 3,
~
0, 1, 2, 3, 4, 5, 6, 
0, 2, 3, 5, 7,
~
0, 1, 2, 4, 5, 
7, 5, 3, 2, 0,
~
1, 2, 4, 5, 
Press any key to continue
+
1, 2, 7, 5, 
+
1, 2, 3, 7, 5, 
+
1, 2, 3, 5, 7, 
+
7, 5, 3, 2, 1, 
 
}}
}}
 

        

        
~
この例を見てわかるように、ArrayListでは要素の数は可変であるため、任意の数の要素を追加・削除・挿入することが出来ます。 要素の追加・削除・挿入には&msdn(netfx,method,System.Collections.ArrayList.Add){Add};, &msdn(netfx,method,System.Collections.ArrayList.AddRange){AddRange};, &msdn(netfx,method,System.Collections.ArrayList.Remove){Remove};, &msdn(netfx,method,System.Collections.ArrayList.RemoveAt){RemoveAt};, &msdn(netfx,method,System.Collections.ArrayList.RemoveRange){RemoveRange};, &msdn(netfx,method,System.Collections.ArrayList.Insert){Insert};などのメソッドを使います。 Removeメソッドは指定された要素をArrayListから削除するのに対し、RemoveAtメソッドは指定されたインデックスにある要素を削除します。 &msdn(netfx,method,System.Collections.ArrayList.Clear){Clearメソッド};によって、コレクション内の全ての要素を削除することも出来ます。 現在の要素の数を取得するには、Lengthプロパティではなく、&msdn(netfx,member,System.Collections.ArrayList.Count){Countプロパティ};を参照します。
この例を見てわかるように、ArrayListはインデックスによる操作ではなくAdd()及びRemove()によって値を追加したり削除したりします。 この例ではint型を代入していますが、ArrayListではobject型を扱うことができるので、どのような型でもArrayListに追加することができます。 Remove()メソッドはそのアイテム自体をArrayListから削除するのに対し、RemoveAt()メソッドは指定されたインデックスのアイテムを削除します。
+

          
+
また、配列と同様に、インデックスを指定して特定の要素を取得・設定することも出来ます。 C#ではインデクサによって、VB.NETでは既定のプロパティItemによって、配列と同様のインデックスによる取得・設定ができるようになっています。
+

          
+
この例ではint型を代入していますが、ArrayListではint型ではなくobject型で要素を格納するので、どのような型でもArrayListに追加することができます。 次の例では、一つのArrayListに様々な型の要素を追加しています。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections;
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    ArrayList arr = new ArrayList();
+

          
+
    arr.Add(16);
+
    arr.Add("foo");
+
    arr.Add(Math.PI);
+

          
+
    Print(arr);
+
  }
+

          
+
  static void Print(ArrayList arr)
+
  {
+
    for (int i = 0; i < arr.Count; i++)
+
    {
+
      Console.Write("{0}, ", arr[i]);
+
    }
+

          
+
    Console.WriteLine();
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim arr As New ArrayList()
+

          
+
    arr.Add(16)
+
    arr.Add("foo")
+
    arr.Add(Math.PI)
+

          
+
    Print(arr)
+
  End Sub
+

          
+
  Shared Sub Print(ByVal arr As ArrayList)
+
    For i As Integer = 0 To arr.Count - 1
+
      Console.Write("{0}, ", arr(i))
+
    Next
+

          
+
    Console.WriteLine()
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
 

        

        
~
#prompt{{
また、ArrayListには便利なメソッドがいくつか含まれていて、Sort()メソッドはアイテムを特定の方法(ここでは大きさ順)で並べ替えたり、Reverse()メソッドで並びを逆にしたりする事もできます。 また、ここでは使用しませんでしたが、アイテム全てを削除するためにClear()メソッドというものも用意されていますし、ArrayListからふつうの配列を作成するToArray()メソッドなども存在します。
+
16, foo, 3.14159265358979,
+
}}
 

        

        
~
***列挙操作
上の例では、Add及びRemoveでアイテムを追加・削除していましたが、C#ではインデクサによってアイテムを追加した後の ArrayListのインデックスで指定されたアイテムに直接アクセスすることができます(VB.NETではこの機能は既定プロパティとしてサポートされています)。 その例が次のコードです(この例では文字列とint型の値をArrayListに同居させています)。
+
ArrayListでも、配列と同様for文による列挙と、foreach文による列挙ができるようになっています。 次の例では、ArrayListをfor文とforeach文で列挙しています。
 

        

        
~
#tabpage(C#)
#code(cs,インデクサによるアクセス){{
+
#code(cs){{
 
using System;
using System;
 
using System.Collections;
using System.Collections;
 

        

        
~
class Sample
namespace Collection
 
{
{
~
  static void Main()
    class Collection
+
  {
+
    ArrayList arr = new ArrayList();
+

          
+
    arr.Add(16);
+
    arr.Add("foo");
+
    arr.Add(Math.PI);
+

          
+
    // for文を使った列挙
+
    for (int i = 0; i < arr.Count; i++)
 
    {
    {
~
      Console.Write("{0}, ", arr[i]);
        [STAThread]
~
    }
        static void Main(string[] args)
~

          
        {
~
    Console.WriteLine();
            // ArrayList のインスタンスを作成
-
            ArrayList arr = new ArrayList();
 

        

        
~
    // foreach文を使った列挙
            arr.Add( 0 );
~
    foreach (object e in arr)
            arr.Add( 1 );
~
    {
            arr.Add( 2 );
~
      Console.Write("{0}, ", e);
            arr.Add( 3 );
~
    }
            arr.Add( 4 );
 

        

        
~
    Console.WriteLine();
            arr[0] = "A";
~
  }
            arr[2] = "B";
~
}
            arr[4] = "C";
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim arr As New ArrayList()
+

          
+
    arr.Add(16)
+
    arr.Add("foo")
+
    arr.Add(Math.PI)
+

          
+
    ' Forステートメントを使った列挙
+
    For i As Integer = 0 To arr.Count - 1
+
      Console.Write("{0}, ", arr(i))
+
    Next
+

          
+
    Console.WriteLine()
+

          
+
    ' For Eachステートメントを使った列挙
+
    For Each e As Object In arr
+
      Console.Write("{0}, ", e)
+
    Next
+

          
+
    Console.WriteLine()
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
 

        

        
~
#prompt{{
            EnumerateArrayList( arr );
~
16, foo, 3.14159265358979, 
        }
+
16, foo, 3.14159265358979, 
+
}}
 

        

        
~
***配列からの変換
        // ArrayListの値を列挙
~
配列からArrayListに変換するには、コンストラクタかAddRangeメソッドが使えます。 既に説明したとおり、配列の型によらずArrayListに変換することができます。
        public static void EnumerateArrayList( ArrayList arr )
-
        {
-
            for ( int i = 0; i < arr.Count; i++ )
-
            {
-
                Console.Write( arr[i].ToString() + ", " );
-
            }
 

        

        
~
#tabpage(C#)
            // 改行
~
#code(cs){{
            Console.Write( Console.Out.NewLine );
~
using System;
        }
+
using System.Collections;
 

        

        
+
class Sample
+
{
+
  static void Main()
+
  {
+
    int[] intArray = new int[] {0, 1, 2};
+
    string[] stringArray = new string[] {"foo", "bar", "baz"};
+

          
+
    // コンストラクタに配列を指定してArrayListを生成
+
    ArrayList arr = new ArrayList(stringArray);
+

          
+
    // AddRangeメソッドで配列を追加
+
    arr.AddRange(intArray);
+

          
+
    Print(arr);
+
  }
+

          
+
  static void Print(ArrayList arr)
+
  {
+
    for (int i = 0; i < arr.Count; i++)
+
    {
+
      Console.Write("{0}, ", arr[i]);
 
    }
    }
+

          
+
    Console.WriteLine();
+
  }
 
}
}
 
}}
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim intArray As Integer() = New Integer() {0, 1, 2}
+
    Dim stringArray As String() = New String() {"foo", "bar", "baz"}
+

          
+
    ' コンストラクタに配列を指定してArrayListを生成
+
    Dim arr As New ArrayList(stringArray)
+

          
+
    ' AddRangeメソッドで配列を追加
+
    arr.AddRange(intArray)
+

          
+
    Print(arr)
+
  End Sub
+

          
+
  Shared Sub Print(ByVal arr As ArrayList)
+
    For i As Integer = 0 To arr.Count - 1
+
      Console.Write("{0}, ", arr(i))
+
    Next
+

          
+
    Console.WriteLine()
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
 

        

        
~
#prompt{{
#prompt(実行結果){{
~
foo, bar, baz, 0, 1, 2, 
A, 1, B, 3, C
-
Press any key to continue
 
}}
}}
 

        

        
~
***配列への変換・コピー
*Hashtable
~
ArrayListから配列へ変換する場合には&msdn(netfx,method,System.Collections.ArrayList.ToArray){ToArrayメソッド};や&msdn(netfx,method,System.Collections.ArrayList.CopyTo){CopyToメソッド};が使えます。 ただしArrayListへの変換とは逆に、配列のコピー時にはコピー先となる配列の型に注意する必要があります。 コピーしようとする要素とコピー先の配列の型が異なる(キャスト出来ない)場合はInvalidCastExceptionがスローされます。
HashtableクラスはArrayList同様、コレクション内の要素数は動的に変化しますが、ArrayListとは異なりキーと呼ばれる値でコレクションにアクセスすることができます。 つまり、インデクサではint値だけでなくすべてのobject値をインデックス(キー)としてとることができます(厳密には全てではなくインスタンスのハッシュ値を取得できるオブジェクト)。 HashtableはPerlなどで連想配列と呼ばれるものに相当します。 Hashtableではキーと値を対にして登録します。
+

          
+
#tabpage(C#)
 
#code(cs){{
#code(cs){{
 
using System;
using System;
 
using System.Collections;
using System.Collections;
 

        

        
~
class Sample
namespace Collection
 
{
{
~
  static void Main()
    class Collection
+
  {
+
    ArrayList arr = new ArrayList();
+

          
+
    arr.Add(1);
+
    arr.Add(2);
+
    arr.Add(3);
+

          
+
    arr.Add("foo");
+
    arr.Add("bar");
+
    arr.Add("baz");
+

          
+
    // ArrayListの0番目から3要素分をintArrayにコピー
+
    int[] intArray = new int[3];
+

          
+
    arr.CopyTo(0, intArray, 0, 3);
+

          
+
    foreach (int intVal in intArray)
 
    {
    {
~
      Console.Write("{0}, ", intVal);
        [STAThread]
~
    }
        static void Main(string[] args)
-
        {
-
            // Hashtable のインスタンスを作成
-
            Hashtable hash = new Hashtable();
 

        

        
~
    Console.WriteLine();
            hash.Add( "A", 1 );
-
            hash.Add( "B", 3 );
-
            hash.Add( "C", 5 );
-
            hash.Add( "D", 7 );
-
            hash.Add( "E", 9 );
 

        

        
~
    // ArrayListの3番目から3要素分をstringArrayにコピー
            Console.Write( hash["E"].ToString() + ", " );
~
    string[] stringArray = new string[3];
            Console.Write( hash["D"].ToString() + ", " );
~

          
            Console.Write( hash["C"].ToString() + ", " );
~
    arr.CopyTo(3, stringArray, 0, 3);
            Console.Write( hash["B"].ToString() + ", " );
~

          
            Console.Write( hash["A"].ToString() + Console.Out.NewLine );
+
    foreach (string stringVal in stringArray)
+
    {
+
      Console.Write("{0}, ", stringVal);
+
    }
 

        

        
~
    Console.WriteLine();
            // Hashtableのキーとして「A」が含まれているか
-
            if ( hash.ContainsKey( "A" ) )
-
            {
-
                Console.WriteLine( "Hashtable contains \"A\" as key" );
-
            }
 

        

        
~
    // ArrayListの全要素をint型配列に変換
            // Hashtableの値として「2」が含まれているか
~
    try
            if ( hash.ContainsValue( "2" ) )
~
    {
            {
~
      intArray = arr.ToArray(typeof(int)) as int[];
                Console.WriteLine( "Hashtable contains \"A\" as value" );
~
    }
            }
~
    catch (InvalidCastException)
        }
+
    {
+
      Console.WriteLine("InvalidCastException");
 
    }
    }
+
  }
 
}
}
 
}}
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim arr As New ArrayList()
+

          
+
    arr.Add(1)
+
    arr.Add(2)
+
    arr.Add(3)
+

          
+
    arr.Add("foo")
+
    arr.Add("bar")
+
    arr.Add("baz")
+

          
+
    ' ArrayListの0番目から3要素分をintArrayにコピー
+
    Dim intArray(2) As Integer
+

          
+
    arr.CopyTo(0, intArray, 0, 3)
 

        

        
~
    For Each intVal As Integer In intArray
#prompt(実行結果){{
~
      Console.Write("{0}, ", intVal)
9, 7, 5, 3, 1
~
    Next
Hashtable contains "A" as key
~

          
Press any key to continue
+
    Console.WriteLine()
+

          
+
    ' ArrayListの3番目から3要素分をstringArrayにコピー
+
    Dim stringArray(2) As String
+

          
+
    arr.CopyTo(3, stringArray, 0, 3)
+

          
+
    For Each stringVal As String In stringArray
+
      Console.Write("{0}, ", stringVal)
+
    Next
+

          
+
    Console.WriteLine()
+

          
+
    ' ArrayListの全要素をint型配列に変換
+
    Try
+
      intArray = DirectCast(arr.ToArray(GetType(Integer)), Integer())
+
    Catch ex As InvalidCastException
+
      Console.WriteLine("InvalidCastException")
+
    End Try
+
  End Sub
+
End Class
 
}}
}}
+
#tabpage-end
 

        

        
~
#prompt{{
この例では文字列をキーとして値を追加しています。 Hashtable内のアイテムにアクセスする場合は、インデクサにキーを指定します(この例では文字列)。 また、特定のオブジェクトがキーまたは値としてHashtableに含まれているかを取得するために、ContainsKey()及び ContainsValue()メソッドが用意されています。 27から36行目のコードはそれを利用したものです。 また、この例では使用しませんでしたが、HashtableにもArrayList同様にRemove()メソッドが存在します。 ただ、このメソッドもインデックスではなくキーで削除するアイテムを指定します。
+
1, 2, 3, 
+
foo, bar, baz, 
+
InvalidCastException
+
}}
 

        

        
~
ToArrayメソッドで型を指定しなければobjectの配列へ変換することが出来ます。 この場合、InvalidCastExceptionはスローされません。
*SortedList
-
SortedListクラスは、HashtableクラスとArrayListクラスの両方の特徴を持っています。 格納しうるアイテム数は増減することができ、ArrayListの様にインデックスでアイテムにアクセスしたりできる一方で、Hashtableのようにキーでアイテムにアクセスすることができます。 実際、どのように動作するか、サンプルを見てみましょう。
 

        

        
+
#tabpage(C#)
 
#code(cs){{
#code(cs){{
 
using System;
using System;
 
using System.Collections;
using System.Collections;
 

        

        
~
class Sample
namespace Collection
 
{
{
~
  static void Main()
    class Collection
+
  {
+
    ArrayList arr = new ArrayList();
+

          
+
    arr.Add(1);
+
    arr.Add(2);
+
    arr.Add(3);
+

          
+
    arr.Add("foo");
+
    arr.Add("bar");
+
    arr.Add("baz");
+

          
+
    object[] objArray = arr.ToArray();
+

          
+
    foreach (object obj in objArray)
 
    {
    {
~
      Console.Write("{0}, ", obj);
        [STAThread]
~
    }
        static void Main(string[] args)
~

          
        {
~
    Console.WriteLine();
            // SortedList のインスタンスを作成
~
  }
            SortedList slist = new SortedList();
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim arr As New ArrayList()
+

          
+
    arr.Add(1)
+
    arr.Add(2)
+
    arr.Add(3)
+

          
+
    arr.Add("foo")
+
    arr.Add("bar")
+
    arr.Add("baz")
+

          
+
    Dim objArray() As Object = arr.ToArray()
+

          
+
    For Each obj As Object In objArray
+
      Console.Write("{0}, ", obj)
+
    Next
+

          
+
    Console.WriteLine()
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
 

        

        
~
#prompt{{
            slist.Add( "加護亜依", 0 );
~
1, 2, 3, foo, bar, baz, 
            slist.Add( "松浦亜弥", 16 );
~
}}
            slist.Add( "後藤真希", 17 );
~

          
            slist.Add( "藤本美貴", 0 );
~
**&aname(Hashtable){Hashtable};
            slist.Add( "矢口真里", 20 );
+
&msdn(netfx,type,System.Collections.Hashtable){System.Collections.Hashtableクラス};はPerlやJavaScriptなどの言語で連想配列と呼ばれるものに相当します。 (Hashtableクラスに相当するジェネリックなコレクションクラスは、[[System.Collections.Generic.Dictionary>#Generic.Dictionary]]クラスです)
 

        

        
~
コレクション内の要素数を動的に増減できる点はArrayListと同じですが、''キー''と''値''を対(ペア)で登録することで、インデックスではなくキーによってコレクション内の要素にアクセスする点でArrayListとは異なります。 Hashtableでは、任意のobject(厳密にはGetHashCodeメソッドが一意なハッシュ値を返すオブジェクト)をキーとして指定することができます。
            // キーによる値の設定
-
            slist["加護亜依"] = 15;
 

        

        
~
***基本的な操作
            // インデックスによる値の設定
~
Hashtableを使った例によって基本的な操作について見ていきます。
            slist.SetByIndex( 3, 18 );
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections;
 

        

        
~
class Sample
            // インデックスによるキーと値の取得
~
{
            for ( int i = 0; i < slist.Count; i++ )
~
  static void Main()
            {
~
  {
                Console.Write( slist.GetKey( i ) + " " );
~
    Hashtable hash = new Hashtable();
                Console.Write( slist.GetByIndex( i ).ToString() + "歳" );
-
                Console.Write( Console.Out.NewLine );
-
            }
 

        

        
~
    hash.Add("foo", 16); // キーを"foo"として値16を追加
            // インデックスの取得
-
            Console.WriteLine( "Index of \"加護亜依\" is {0}", slist.IndexOfKey( "加護亜依" ) ); 
 

        

        
~
    hash["bar"] = 72; // キー"bar"の値として値72を設定
            Console.WriteLine( "Index of 18-years-old girl is {0}", slist.IndexOfValue( 18 ) ); 
+
    hash["baz"] = 42; // キー"baz"の値として値42を設定
 

        

        
~
    Console.WriteLine(hash["foo"]); // キー"foo"の値を取得
        }
~
    Console.WriteLine(hash["bar"]); // キー"bar"の値を取得
    }
+
    Console.WriteLine(hash["baz"]); // キー"baz"の値を取得
+

          
+
    Console.WriteLine(hash["hoge"] == null); // キー"hoge"の値を取得
+

          
+
    Console.WriteLine(hash[0] == null); // 数値0はインデックスではなくキーとして扱われる
+

          
+
    Console.WriteLine(hash.Count); // 現在のキーと値の対の数を取得
+
  }
 
}
}
 
}}
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim hash As New Hashtable()
+

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

          
+
    hash("bar") = 72 ' キー"bar"の値として値72を設定
+
    hash("baz") = 42 ' キー"baz"の値として値42を設定
+

          
+
    Console.WriteLine(hash("foo")) ' キー"foo"の値を取得
+
    Console.WriteLine(hash("bar")) ' キー"bar"の値を取得
+
    Console.WriteLine(hash("baz")) ' キー"baz"の値を取得
+

          
+
    Console.WriteLine(hash("hoge") Is Nothing) ' キー"hoge"の値を取得
+

          
+
    Console.WriteLine(hash(0) Is Nothing) ' 数値0はインデックスではなくキーとして扱われる
+

          
+
    Console.WriteLine(hash.Count) ' 現在のキーと値の対の数を取得
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
 

        

        
~
#prompt{{
#prompt(実行結果){{
~
16
加護亜依 15歳
~
72
後藤真希 17歳
~
42
松浦亜弥 16歳
~
True
藤本美貴 18歳
~
True
矢口真里 20歳
~
3
Index of "加護亜依" is 0
-
Index of 18-years-old girl is 3
-
Press any key to continue
 
}}
}}
 

        

        
~
この例ではキーとして文字列、値として数値を使ってHashtableを操作しています。 Hashtable内の要素を取得・設定するには、インデクサにキーを指定します。 設定の際、キーに該当するの要素が無ければ、追加されます。 取得の際、キーに該当する要素がない場合は、null(Nothing)が変えされます(IndexOutOfRangeExceptionがスローされることはありません)。 また、ArrayList同様、&msdn(netfx,method,System.Collections.Hashtable.Add){Add};, &msdn(netfx,method,System.Collections.Hashtable.Remove){Remove};, &msdn(netfx,method,System.Collections.Hashtable.Clear){Clear};などのメソッドによってキーと値の対を追加、削除、クリアすることも出来ます。
先ほど説明したとおり、キーとインデックスといずれの方法でも値を設定ることができます。 また、インデックスからキー・値を取得することができます。 さらに、キーまたは値からインデックスを取得することができます。 このようにHashtableやArrayListよりも柔軟にアイテムにアクセスすることができるという便利な反面、適切な場面で使わないと逆に混乱を招きそうです。 今回も使用しませんでしたが、SortedListにはキーによりアイテムを削除するRemove()メソッドと、インデックスにより削除するRemoveAt()メソッドの二種類が存在します。
 

        

        
~
***列挙操作
*BitArray
~
Hashtableの場合も、foreach文によって要素を列挙することができますが、ArrayListなどとは異なり常にキーと値のペアが列挙されます。 Hashtableの内部では個々のペアは&msdn(netfx,type,System.Collections.DictionaryEntry){DictionaryEntry構造体};として格納されるので、foreach文ではDictionaryEntry構造体を使います。 DictionaryEntry構造体のKeyプロパティとValueプロパティを参照することで、キーと値を参照できます。 列挙の際、必ずしも追加した順で列挙されるとは限らない点に注意が必要です。
BitArrayクラスは今までのクラスとは異なり、ビット値を扱います。 BitArrayでは、一つ一つのアイテムがboolean型からなり、各ビットを扱います。 これによりビットごとの計算などを容易に行えます。 次のサンプルはbyte型の配列とint型の配列からBitArrayのインスタンスを作成し、8ビットまたは32ビット毎にその値を出力させるものです。
 

        

        
+
また、Hashtableに格納されているすべてのキーは&msdn(netfx,member,System.Collections.Hashtable.Keys){Keysプロパティ};、値は&msdn(netfx,member,System.Collections.Hashtable.Values){Valuesプロパティ};を通して参照できます。
+

          
+
#tabpage(C#)
 
#code(cs){{
#code(cs){{
 
using System;
using System;
 
using System.Collections;
using System.Collections;
 

        

        
~
class Sample
namespace Collection
 
{
{
~
  static void Main()
    class Collection
+
  {
+
    Hashtable hash = new Hashtable();
+

          
+
    hash["foo"] = 16;
+
    hash["bar"] = 72;
+
    hash["baz"] = 42;
+

          
+
    // Hashtableに格納されているキーと値のペアを列挙
+
    foreach (DictionaryEntry entry in hash)
+
    {
+
      Console.WriteLine("{0} => {1}", entry.Key, entry.Value);
+
    }
+

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

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

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

          
+
    foreach (object val in hash.Values)
 
    {
    {
~
      Console.WriteLine(val);
        [STAThread]
~
    }
        static void Main(string[] args)
~
  }
        {
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim hash As New Hashtable()
+

          
+
    hash("foo") = 16
+
    hash("bar") = 72
+
    hash("baz") = 42
+

          
+
    ' Hashtableに格納されているキーと値のペアを列挙
+
    For Each entry As DictionaryEntry In hash
+
      Console.WriteLine("{0} => {1}", entry.Key, entry.Value)
+
    Next
+

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

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

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

          
+
    For Each val As Object In hash.Values
+
      Console.WriteLine(val)
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
 

        

        
~
#prompt{{
            // byte型の配列を作成
~
foo => 16
            byte [] bytArray = { 0, 1, 2, 3, 4 }; 
+
baz => 42
+
bar => 72
+
[Keys]
+
foo
+
baz
+
bar
+
[Values]
+
16
+
42
+
72
+
}}
 

        

        
~
***配列へのコピー
            // BitArray のインスタンスを作成
~
列挙の場合と同様、&msdn(netfx,method,System.Collections.Hashtable.CopyTo){CopyToメソッド};でHashtableの内容を配列にコピーする場合も、DictionaryEntry構造体としてコピーされます。 キーのみをコピーしたい場合はKeysプロパティのCopyTo、値のみをコピーしたい場合はValuesプロパティのCopyToメソッドを使う必要があります。 当然ながら、キー・値の型とコピー先配列の型が合わない場合はInvalidCastExceptionがスローされます。
            BitArray barr = new BitArray( bytArray );
 

        

        
~
#tabpage(C#)
            // 列挙
~
#code(cs){{
            Console.WriteLine( "BitArray from byte-Array." );
+
using System;
+
using System.Collections;
 

        

        
~
class Sample
            EnumerateBitArray( barr, 8 );
+
{
+
  static void Main()
+
  {
+
    Hashtable hash = new Hashtable();
 

        

        
+
    hash["foo"] = 16;
+
    hash["bar"] = 72;
+
    hash["baz"] = 42;
 

        

        
~
    // Hashtableのすべてのペアを配列にコピー
            // int型の配列を作成
~
    DictionaryEntry[] entries = new DictionaryEntry[hash.Count];
            int [] intArray = { 0x100, 0x200, 0x400, 0x800, 0x1000 }; 
 

        

        
~
    hash.CopyTo(entries, 0);
            // 新たな BitArray のインスタンスを作成
-
            barr = new BitArray( intArray );
 

        

        
~
    for (int i = 0; i < entries.Length; i++)
            // 列挙
~
    {
            Console.WriteLine( "BitArray from int-Array." );
+
      Console.WriteLine("Entries[{0}]: {1} => {2}", i, entries[i].Key, entries[i].Value);
+
    }
 

        

        
~
    // Hashtableのすべてのキーを配列にコピー
            EnumerateBitArray( barr, 32 );
+
    string[] keys = new string[hash.Count];
 

        

        
~
    hash.Keys.CopyTo(keys, 0);
        }
 

        

        
~
    for (int i = 0; i < keys.Length; i++)
        // BitArrayを列挙
~
    {
        public static void EnumerateBitArray( BitArray barr, int length )
~
      Console.WriteLine("Keys[{0}]: {1}", i, keys[i]);
        {
~
    }
            for ( int i = 0; i < barr.Count; i++ )
-
            {
-
                // true を 1、false を 0として出力
-
                int iValue = barr[i] ? 1 : 0;
 

        

        
~
    // Hashtableのすべての値を配列にコピー
                Console.Write( iValue.ToString() );
+
    int[] values = new int[hash.Count];
 

        

        
~
    hash.Values.CopyTo(values, 0);
                // length桁表示したら改行
-
                if ( i % length == length - 1 ) Console.Write( Console.Out.NewLine );
-
            }
-
        }
 

        

        
+
    for (int i = 0; i < values.Length; i++)
+
    {
+
      Console.WriteLine("Values[{0}]: {1}", i, values[i]);
 
    }
    }
+
  }
 
}
}
 
}}
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim hash As New Hashtable()
+

          
+
    hash("foo") = 16
+
    hash("bar") = 72
+
    hash("baz") = 42
+

          
+
    ' Hashtableのすべてのペアを配列にコピー
+
    Dim entries(hash.Count - 1) As DictionaryEntry
+

          
+
    hash.CopyTo(entries, 0)
 

        

        
~
    For i As Integer = 0 To entries.Length - 1
#prompt(実行結果){{
~
      Console.WriteLine("Entries[{0}]: {1} => {2}", i, entries(i).Key, entries(i).Value)
BitArray from byte-Array.
~
    Next
00000000
~

          
10000000
~
    ' Hashtableのすべてのキーを配列にコピー
01000000
~
    Dim keys(hash.Count - 1) As String
11000000
~

          
00100000
~
    hash.Keys.CopyTo(keys, 0)
BitArray from int-Array.
~

          
00000000100000000000000000000000
~
    For i As Integer = 0 To keys.Length - 1
00000000010000000000000000000000
~
      Console.WriteLine("Keys[{0}]: {1}", i, keys(i))
00000000001000000000000000000000
~
    Next
00000000000100000000000000000000
~

          
00000000000010000000000000000000
~
    ' Hashtableのすべての値を配列にコピー
Press any key to continue
+
    Dim values(hash.Count - 1) As Integer
+

          
+
    hash.Values.CopyTo(values, 0)
+

          
+
    For i As Integer = 0 To values.Length - 1
+
      Console.WriteLine("Keys[{0}]: {1}", i, values(i))
+
    Next
+
  End Sub
+
End Class
 
}}
}}
+
#tabpage-end
 

        

        
~
#prompt{{
このように、byteないしint型の配列に格納された各値から一ビットずつ読み取り、BitArrayインスタンスが作成されます(コンストラクタの種類はいくつかありますが、ここでは説明しません)。 実行結果は出力処理の関係上、左が下位ビットになっていますが、各値のビット表記が成されています。 EnumerateBitArray()メソッドでは、BitArrayの各アイテムの値のtrueとfalseを0と1に置き換え、byte型では 1Byte-8Bit、int型では4Byte-32Bitなのでその桁数毎に改行するようにしています。
+
Entries[0]: foo => 16
+
Entries[1]: baz => 42
+
Entries[2]: bar => 72
+
Keys[0]: foo
+
Keys[1]: baz
+
Keys[2]: bar
+
Values[0]: 16
+
Values[1]: 42
+
Values[2]: 72
+
}}
 

        

        
~
***ContainsKey, ContainsValue
さらに、BitArrayはビット毎の配列化だけでなく、他のBitArrayとのビット毎の演算を行うこともできます。 そのサンプルが次のコードです。
+
Hashtableに指定したキーを持つ要素が格納されているかどうかを調べるには&msdn(netfx,method,System.Collections.Hashtable.ContainsKey){ContainsKeyメソッド};、値が格納されているか調べるには&msdn(netfx,method,System.Collections.Hashtable.ContainsValue){ContainsValueメソッド};を使います。
 

        

        
+
#tabpage(C#)
 
#code(cs){{
#code(cs){{
 
using System;
using System;
 
using System.Collections;
using System.Collections;
 

        

        
~
class Sample
namespace Collection
 
{
{
~
  static void Main()
    class Collection
~
  {
    {
~
    Hashtable hash = new Hashtable();
        [STAThread]
~

          
        static void Main(string[] args)
~
    hash["foo"] = 16;
        {
+
    hash["bar"] = 72;
+
    hash["baz"] = 42;
+

          
+
    // キー"foo"を持つ要素があるかどうか
+
    Console.WriteLine(hash.ContainsKey("foo"));
+

          
+
    // キー"hoge"を持つ要素があるかどうか
+
    Console.WriteLine(hash.ContainsKey("hoge"));
+

          
+
    // 値16を持つ要素があるかどうか
+
    Console.WriteLine(hash.ContainsValue(16));
+

          
+
    // 値9を持つ要素があるかどうか
+
    Console.WriteLine(hash.ContainsValue(9));
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim hash As New Hashtable()
+

          
+
    hash("foo") = 16
+
    hash("bar") = 72
+
    hash("baz") = 42
+

          
+
    ' キー"foo"を持つ要素があるかどうか
+
    Console.WriteLine(hash.ContainsKey("foo"))
+

          
+
    ' キー"hoge"を持つ要素があるかどうか
+
    Console.WriteLine(hash.ContainsKey("hoge"))
+

          
+
    ' 値16を持つ要素があるかどうか
+
    Console.WriteLine(hash.ContainsValue(16))
+

          
+
    ' 値9を持つ要素があるかどうか
+
    Console.WriteLine(hash.ContainsValue(9))
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
True
+
False
+
True
+
False
+
}}
+

          
+
なお、IDictionaryインターフェイスのメソッドを実装したContainsメソッドも用意されていますが、これとContainsKeyの動作は全く同じです。
+

          
+
***キー比較のカスタマイズ
+
コンストラクタで適切なIEqualityComparerインターフェイスを指定することで、Hashtableのキー比較時の動作をカスタマイズ出来ます。 例えば、文字列をキーとした場合に大文字小文字を無視するようにするといったことが出来ます。 以下は、&msdn(netfx,type,System.StringComparer){StringComparerクラス};を使って、大文字小文字を無視するHashtableを作成する例です。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections;
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    // 大文字小文字の違いを無視しないHashtableを作成
+
    // (キーの比較にStringComparer.CurrentCultureを使用)
+
    Hashtable caseSensitiveHash = new Hashtable(StringComparer.CurrentCulture);
+

          
+
    caseSensitiveHash["foo"] = 1;
+
    caseSensitiveHash["bar"] = 2;
+
    caseSensitiveHash["FOO"] = 3;
+
    caseSensitiveHash["BAR"] = 4;
+

          
+
    // 大文字小文字の違いを無視するHashtableを作成
+
    // (キーの比較にStringComparer.CurrentCultureIgnoreCaseを使用)
+
    Hashtable caseInsensitiveHash = new Hashtable(StringComparer.CurrentCultureIgnoreCase);
+

          
+
    caseInsensitiveHash["foo"] = 1;
+
    caseInsensitiveHash["bar"] = 2;
+
    caseInsensitiveHash["FOO"] = 3;
+
    caseInsensitiveHash["BAR"] = 4;
+

          
+
    Console.WriteLine("caseSensitiveHash");
 

        

        
~
    foreach (DictionaryEntry entry in caseSensitiveHash)
            // byte型の配列を作成
~
    {
            byte [] bytArray1 = { 0x5d }; 
~
      Console.WriteLine("{0} => {1}", entry.Key, entry.Value);
            byte [] bytArray2 = { 0x7a }; 
+
    }
 

        

        
~
    Console.WriteLine("caseInsensitiveHash");
            // BitArray のインスタンスを作成
-
            BitArray barr1 = new BitArray( bytArray1 );
-
            BitArray barr2 = new BitArray( bytArray2 );
 

        

        
~
    foreach (DictionaryEntry entry in caseInsensitiveHash)
            // 計算結果代入用
~
    {
            BitArray barrResult;
+
      Console.WriteLine("{0} => {1}", entry.Key, entry.Value);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' 大文字小文字の違いを無視しないHashtableを作成
+
    ' (キーの比較にStringComparer.CurrentCultureを使用)
+
    Dim caseSensitiveHash As New Hashtable(StringComparer.CurrentCulture)
+

          
+
    caseSensitiveHash("foo") = 1
+
    caseSensitiveHash("bar") = 2
+
    caseSensitiveHash("FOO") = 3
+
    caseSensitiveHash("BAR") = 4
+

          
+
    ' 大文字小文字の違いを無視するHashtableを作成
+
    ' (キーの比較にStringComparer.CurrentCultureIgnoreCaseを使用)
+
    Dim caseInsensitiveHash As New Hashtable(StringComparer.CurrentCultureIgnoreCase)
+

          
+
    caseInsensitiveHash("foo") = 1
+
    caseInsensitiveHash("bar") = 2
+
    caseInsensitiveHash("FOO") = 3
+
    caseInsensitiveHash("BAR") = 4
+

          
+
    Console.WriteLine("caseSensitiveHash")
+

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

          
+
    Console.WriteLine("caseInsensitiveHash")
+

          
+
    For Each entry As DictionaryEntry In caseInsensitiveHash
+
      Console.WriteLine("{0} => {1}", entry.Key, entry.Value)
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
 

        

        
~
#prompt{{
            // 列挙
~
caseSensitiveHash
            Console.Write( "0x5d: " ); EnumerateBitArray( barr1, 8 );
~
BAR => 4
            Console.Write( "0x7a: " ); EnumerateBitArray( barr2, 8 );
~
bar => 2
            
~
foo => 1
            // 各種演算
~
FOO => 3
            barrResult = (BitArray)barr1.Clone();
~
caseInsensitiveHash
            barrResult.Or( barr2 );
+
bar => 4
+
foo => 3
+
}}
 

        

        
~
**&aname(SortedList){SortedList};
            Console.WriteLine( "BitArray1 Or BitArray2" );
~
&msdn(netfx,type,System.Collections.SortedList){System.Collections.SortedListクラス};は、HashtableクラスとArrayListクラスの両方の特徴を持ったコレクションです。 Hashtableと同じようにキーと値のペアで要素が格納され、キーによってコレクション内の要素にアクセスできるという点に加え、ArrayListのようにインデックスを指定して要素にアクセスすることができます。 また、SortedListという名前が示すとおり、要素が追加される時点でSortedListの内容はキーに基づいてソートされる点でHashtableと異なります。 (SortedListクラスに相当するジェネリックなコレクションクラスは、[[System.Collections.Generic.SortedList>#Generic.SortedListSortedDictionary]]クラスです)
            EnumerateBitArray( barrResult, 8 );
 

        

        
~
***基本的な操作
            barrResult = (BitArray)barr1.Clone();
~
多くの操作はHashtableと同様ですが、SortedListを使った例によって基本的な操作について見ていきます。
            barrResult.And( barr2 );
 

        

        
~
#tabpage(C#)
            Console.WriteLine( "BitArray1 And BitArray2" );
~
#code(cs){{
            EnumerateBitArray( barrResult, 8 );
+
using System;
+
using System.Collections;
 

        

        
~
class Sample
            barrResult = (BitArray)barr1.Clone();
~
{
            barrResult.Xor( barr2 );
+
  static void Main()
+
  {
+
    SortedList list = new SortedList();
 

        

        
~
    // キーを"foo"として値16を追加
            Console.WriteLine( "BitArray1 Xor BitArray2" );
~
    list.Add("foo", 16);
            EnumerateBitArray( barrResult, 8 );
 

        

        
~
    list["bar"] = 72; // キー"bar"の値として値72を設定
            barrResult = (BitArray)barr1.Clone();
-
            barrResult.Not();
 

        

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

        

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

        

        
~
    // インデックス1の要素の値を取得
        // BitArrayを列挙
~
    list.SetByIndex(1, "hoge");
        public static void EnumerateBitArray( BitArray barr, int length )
-
        {
-
            for ( int i = 0; i < barr.Count; i++ )
-
            {
-
                // true を 1、false を 0として出力
-
                int iValue = barr[i] ? 1 : 0;
 

        

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

        

        
~
    // キー"foo", "bar"の要素が格納されているインデックスを取得
                // length桁表示したら改行
~
    Console.WriteLine("IndexOfKey 'foo' => {0}", list.IndexOfKey("foo"));
                if ( i % length == length - 1 ) Console.Write( Console.Out.NewLine );
~
    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));
+
  }
 
}
}
 
}}
}}
+
#tabpage(VB)
+
#code(vb){{
+
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
+
}}
+
#tabpage-end
 

        

        
~
#prompt{{
#prompt(実行結果){{
~
foo => 16
0x5d: 10111010
~
bar => 72
0x7a: 01011110
~
0 = 72
BitArray1 Or BitArray2
~
1 = 16
11111110
~
foo => hoge
BitArray1 And BitArray2
~
bar => 72
00011010
~
IndexOfKey 'foo' => 1
BitArray1 Xor BitArray2
~
IndexOfKey 'bar' => 0
11100100
~
IndexOfValue 16 => -1
Not BitArray1
~
IndexOfValue 72 => 0
01000101
-
Press any key to continue
 
}}
}}
 

        

        
~
例で示したとおり、キーによるアクセスの場合はHashtableと同様にインデクサを用いて行い、インデックスによるアクセスの場合は&msdn(netfx,method,System.Collections.SortedList.GetByIndex){GetByIndexメソッド};と&msdn(netfx,method,System.Collections.SortedList.SetByIndex){SetByIndexメソッド};を用いて行います。 インデクサにインデックスを指定しても、キーとしてしか扱われないので注意してください。
このように、数種の演算も容易にできてしまうのですが、C++プログラマなどビット演算に慣れている玄人さんからすれば、あまり価値の高い機能ではないかもしれません。
 

        

        
~
また、キーに該当する要素のインデックス、値に該当する要素のインデックスを取得するには、&msdn(netfx,method,System.Collections.SortedList.IndexOfKey){IndexOfKeyメソッド};と&msdn(netfx,method,System.Collections.SortedList.IndexOfValue){IndexOfValueメソッド};を使います。 該当するキーまたは値が見つからない場合は-1が返されます。
*Stack
-
これから説明するStackとこの次で説明するQueueは、今までのコレクションクラスとは少し性格の異なるものです。 StackとQueueは ArrayListやHashtableなどとは異なり、コレクションにどのようなオブジェクトが格納されているかということより、どのような順番で格納されたかと言うことの方が重要視されます。 これらStackやQueueなどのデータ構造はC++などではお馴染みでSTLなどにも組み込まれているので、既に知っている方もいるかもしれません。 .NET FrameworkにおけるStackの概要を説明すると次のようなものです。
-
#ref(00.png,スタック)
-
スタックは一見ArrayListなどのコレクションと同じ様に見えますが、アイテムの追加の仕方が違います。 スタックは後入れ先出し(LIFO: Last-In, First-Out)のデータ構造と言われます。 スタックにおいては、アイテムを追加することをPush、アイテムを取り出すことをPopといい、 Pushする際にはスタックの一番末尾に追加し、Popする際にはスタックの一番末尾から取り出します。 左の図がそのことを表しています。 イメージしづらい方は、本を一冊ずつ積み上げる作業がPush、積まれた本を一冊ずつ上から取っていく作業がPopに相当すると思って下さい。
 

        

        
~
この例では使用していませんが、キーによる要素の削除には&msdn(netfx,method,System.Collections.SortedList.Remove){Removeメソッド};、インデックスによる要素の削除には&msdn(netfx,method,System.Collections.SortedList.RemoveAt){RemoveAtメソッド};を使用します。 Hashtableと同様、&msdn(netfx,method,System.Collections.SortedList.ContainsKey){ContainsKeyメソッド};、&msdn(netfx,method,System.Collections.SortedList.ContainsValue){ContainsValueメソッド};も用意されています。
.NET Frameworkでは、スタックは最初既定の容量(入れられるアイテムの最大数)をもっています。 これを越えてPushしようとすると、スタックの容量は拡充されます(拡充されずに、一番古いアイテムは破棄されるスタックもあります)。 現在何アイテムあるかを知るプロパティがCountです。 拡充された後、Popによってアイテム数が減っても、スタックの容量は減ることはありません。 また、.NET FrameworkのStackクラスにはPeek()というメソッドがあり、このメソッドはスタックからアイテムを取り出すことなく末尾のアイテムを参照するためのメソッドです。
 

        

        
~
***列挙操作
では、実際にStackクラスを使ったサンプルを組んでみます。
+
SortedListの列挙もHashtableでの列挙と同様、DictionaryEntryに格納たキーと値のペアで列挙されますが、ソート済みの状態で列挙される点がHashtableとは異なります。 また、Hashtableと同様に、SortedListに格納されているすべてのキーは&msdn(netfx,member,System.Collections.SortedList.Keys){Keysプロパティ};、値は&msdn(netfx,member,System.Collections.SortedList.Values){Valuesプロパティ};を通して参照できます。
 

        

        
+
#tabpage(C#)
 
#code(cs){{
#code(cs){{
 
using System;
using System;
 
using System.Collections;
using System.Collections;
 

        

        
~
class Sample
namespace Collection
 
{
{
~
  static void Main()
    class Collection
+
  {
+
    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);
        [STAThread]
~
    }
        static void Main(string[] args)
~

          
        {
~
    // 同じ内容のHashtableを作成して列挙
            // Stack のインスタンスを作成
~
    Hashtable hash = new Hashtable(list);
            Stack st = new Stack();
 

        

        
~
    Console.WriteLine("Hashtable");
            // Stack に値をPush
~

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

        

        
~
    // SortedListに格納されているすべてのキーを列挙
            for ( int i = 0; i < 10; i++ )
~
    Console.WriteLine("[Keys]");
            {
-
                st.Push( i );
-
            }
 

        

        
~
    foreach (object key in list.Keys)
            
~
    {
            // 末尾のアイテムを参照
~
      Console.WriteLine(key);
            Console.WriteLine( "Last item of stack is {0}", (int)st.Peek() );
+
    }
 

        

        
~
    // SortedListに格納されているすべての値を列挙
            // Stack から値がなくなるまでPop
~
    Console.WriteLine("[Values]");
            Console.WriteLine( "Popping..." );
 

        

        
~
    foreach (object val in list.Values)
            while ( 0 < st.Count )
~
    {
            {
~
      Console.WriteLine(val);
                Console.WriteLine( (int)st.Pop() );
-
            }
-
        }
 
    }
    }
+
  }
 
}
}
 
}}
}}
~
#tabpage(VB)

          
~
#code(vb){{
#prompt(実行結果){{
~
Imports System
ushing...
~
Imports System.Collections
Last item of stack is 9
~

          
Popping...
~
Class Sample
9
~
  Shared Sub Main()
8
~
    Dim list As New SortedList()
7
~

          
6
~
    list("foo") = 16
5
~
    list("bar") = 72
4
~
    list("baz") = 42
3
~

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

          
Press any key to continue
+
    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
 
}}
}}
+
#tabpage-end
 

        

        
~
#prompt{{
このサンプルでは、スタックに0から9の値をPushし、すぐに追加した回数だけPopしています。 スタックの一番最後に入れたアイテムは一番始めに取り出されるという特性上、アイテムを入れた順番とは逆の順番で表示されています。
+
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の場合はキーによってソートされている点に注目してください。
*Queue
-
キューはスタックと似たような構造なのですが、アイテムの取り出し方が異なります。 スタックは後入れ先出しであったのに対し、キューは先入れ先出し (FIFO: First-In, First-Out)のデータ構造と言われます。 キューにおいては、アイテムを追加することをEnqueue、アイテムを取り出すことをDequeue といい、Enququeする際にはキューの一番末尾に追加し、Dequeueする際にはキューの一番先頭から取り出します。 左の図がそのことを表しています。 イメージしづらい方は、おいしいと評判の店の待ち行列を想像して下さい。 客が一人一人と並んでいく様がEnqueue、やっとのことで店に入り、満足のうちに店を去る様がDequeueに相当すると思って下さい。
-
#ref(01.png,スタック)
-
.NET Frameworkでは、スタック同様キューも最初既定の容量をもっています。 これを越えてEnqueueしようとすると、キューの容量は拡充されます(これもスタック同様、拡充されずに、一番古いアイテムは破棄されるキューもあります)。 スタック同様にキューにもCountプロパティが存在します。 拡充された後、Dequeueによってアイテム数が減っても、キューのの容量は減ることはありません。 また、スタック同様Queueクラスにも Peek()というメソッドがあります。
 

        

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

        

        
+
#tabpage(C#)
 
#code(cs){{
#code(cs){{
 
using System;
using System;
 
using System.Collections;
using System.Collections;
 

        

        
~
// アルファベット順とは逆順にソートするためのIComparer
namespace Collection
+
class ReverseStringComparer : IComparer
 
{
{
~
  public int Compare(object x, object y)
    class Collection
~
  {
    {
~
    // StringComparer.CurrentCulture.Compareとは逆の結果を返すようにする
        [STAThread]
~
    return -1 * StringComparer.CurrentCulture.Compare(x, y);
        static void Main(string[] args)
~
  }
        {
~
}
            // Queue のインスタンスを作成
~

          
            Queue qu = new Queue(5);
+
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());
            // Queue に値をEnqueue
-
            Console.WriteLine( "Enqueuing..." );
 

        

        
~
    reverseOrderdList["Alice"]    = 1;
            for ( int i = 0; i < 10; i++ )
~
    reverseOrderdList["Bob"]      = 2;
            {
~
    reverseOrderdList["Charlie"]  = 3;
                qu.Enqueue( i );
~
    reverseOrderdList["Dave"]     = 4;
            }
 

        

        
~
    Console.WriteLine("orderdList");
            
~

          
            // 末尾のアイテムを参照
~
    foreach (DictionaryEntry entry in orderdList)
            Console.WriteLine( "Last item of queue is {0}", (int)qu.Peek() );
+
    {
+
      Console.WriteLine("{0,-7} => {1}", entry.Key, entry.Value);
+
    }
 

        

        
~
    Console.WriteLine("reverseOrderdList");
            // Queue から値がなくなるまでDequeue
-
            Console.WriteLine( "Dequeuing..." );
 

        

        
~
    foreach (DictionaryEntry entry in reverseOrderdList)
            while ( 0 < qu.Count )
~
    {
            {
~
      Console.WriteLine("{0,-7} => {1}", entry.Key, entry.Value);
                Console.WriteLine( (int)qu.Dequeue() );
-
            }
-
        }
 
    }
    }
+
  }
 
}
}
 
}}
}}
+
#tabpage(VB)
+
#code(vb){{
+
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
+
}}
+
#tabpage-end
 

        

        
~
#prompt{{
#prompt(実行結果){{
~
orderdList
Enqueuing...
~
Alice   => 1
Last item of queue is 0
~
Bob     => 2
Dequeuing...
~
Charlie => 3
0
~
Dave    => 4
1
~
reverseOrderdList
2
~
Dave    => 4
3
~
Charlie => 3
4
~
Bob     => 2
5
~
Alice   => 1
6
-
7
-
8
-
9
-
Press any key to continue
 
}}
}}
 

        

        
~
**&aname(Stack){Stack};
このサンプルはスタックのサンプルと同様に、キューに0から9の値をEnqueueし、すぐに追加した回数だけDequeueしています。 キューの一番最初に入れたアイテムは一番始めに取り出されるという特性上、アイテムを入れた順番と同じ順番で表示されています。
+
&msdn(netfx,type,System.Collections.Stack){System.Collections.Stackクラス};は、後入れ先出し(LIFO: Last-In, First-Out)のデータ構造を持つ''スタック''を提供するコレクションクラスです。 Stackクラスと次に説明するQueueクラスでは、ArrayListクラスやHashtableクラスとは異なり、コレクションにどのようなオブジェクトが格納されているかということより、どのような順番で格納されたかと言うことの方が重要視されます。 (Stackクラスに相当するジェネリックなコレクションクラスは、[[System.Collections.Generic.Stack>#Generic.Stack]]クラスです)
+

          
+
***基本的な操作
+
#ref(00.png,スタック)
+
.NET FrameworkにおけるStackクラスの概要を見ていきます。 Stackに要素を追加する''プッシュ''の操作は&msdn(netfx,method,System.Collections.Stack.Push){Pushメソッド};、Stackから要素を取り出す''ポップ''の操作は&msdn(netfx,method,System.Collections.Stack.Pop){Popメソッド};で行います。 Stackから要素を''ポップ''すると、取り出した要素はStackから削除されます。 本を一冊ずつ積み上げる作業が''プッシュ''、積まれた本を一冊ずつ上から取っていく作業が''ポップ''に相当するとイメージするとよいと思います。
+

          
+
また、&msdn(netfx,method,System.Collections.Stack.Peek){Peekメソッド};を使うと、Stackの内容はそのままで(削除されずに)先頭にある要素を取得できます。 Stackの内容が空の場合に、PopメソッドやPeekメソッドを呼び出すとInvalidOperationExceptionがスローされます。 Stackの内容を空にするには、&msdn(netfx,method,System.Collections.Stack.Clear){Clearメソッド};を使います。 Stackに指定した内容の要素が含まれているか調べるには、&msdn(netfx,method,System.Collections.Stack.Contains){Containsメソッド};を使います。
+

          
+
Stackに現在いくつの要素が含まれているかを知るには&msdn(netfx,member,System.Collections.Stack.Count){Countプロパティ};を参照します。 ArrayListなどと同様、Stackには任意の数の要素をプッシュできます。 Stack内部の容量はプッシュの際に自動的に拡充されます。 ポップの際に要素数が減っても、Stack内部で確保されている容量は減ることはありません。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections;
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    Stack s = new Stack();
+

          
+
    // Stackに要素をPush
+
    s.Push("Alice");
+
    s.Push("Bob");
+
    s.Push("Charlie");
+
    s.Push("Dave");
+
    s.Push("Eve");
+

          
+
    Console.WriteLine("Count: {0}", s.Count);
+

          
+
    // Stackの先頭にある要素をPeek
+
    Console.WriteLine("Peek: {0}", s.Peek());
+

          
+
    Console.WriteLine("Count: {0}", s.Count);
 

        

        
~
    // Stackの先頭にある要素をPop
このように、System.Collection名前空間には様々なコレクションクラスが存在するので、それぞれの特長を生かしてコーディングすることができます。 QueueやStackなどのデータ構造は有名なもので、いろいろなところで応用されています。 もっと詳しく知りたい方は調べてみると良いでしょう。
+
    Console.WriteLine("Pop: {0}", s.Pop());
+
    Console.WriteLine("Pop: {0}", s.Pop());
+

          
+
    Console.WriteLine("Count: {0}", s.Count);
+

          
+
    // Stackに"Alice", "Eve"が含まれるか調べる
+
    Console.WriteLine(s.Contains("Alice"));
+
    Console.WriteLine(s.Contains("Eve"));
+

          
+
    // Stackに"Fran", "Gordon"をPush
+
    s.Push("Fran");
+
    s.Push("Gordon");
+

          
+
    Console.WriteLine();
+

          
+
    // Stackが空になるまで内容をPop
+
    while (0 < s.Count)
+
    {
+
      Console.WriteLine(s.Pop());
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim s As New Stack()
+

          
+
    ' Stackに要素をPush
+
    s.Push("Alice")
+
    s.Push("Bob")
+
    s.Push("Charlie")
+
    s.Push("Dave")
+
    s.Push("Eve")
+

          
+
    Console.WriteLine("Count: {0}", s.Count)
+

          
+
    ' Stackの先頭にある要素をPeek
+
    Console.WriteLine("Peek: {0}", s.Peek())
+

          
+
    Console.WriteLine("Count: {0}", s.Count)
+

          
+
    ' Stackの先頭にある要素をPop
+
    Console.WriteLine("Pop: {0}", s.Pop())
+
    Console.WriteLine("Pop: {0}", s.Pop())
+

          
+
    Console.WriteLine("Count: {0}", s.Count)
+

          
+
    ' Stackに"Alice", "Eve"が含まれるか調べる
+
    Console.WriteLine(s.Contains("Alice"))
+
    Console.WriteLine(s.Contains("Eve"))
+

          
+
    ' Stackに"Fran", "Gordon"をPush
+
    s.Push("Fran")
+
    s.Push("Gordon")
+

          
+
    Console.WriteLine()
+

          
+
    ' Stackが空になるまで内容をPop
+
    While 0 < s.Count
+
      Console.WriteLine(s.Pop())
+
    End While
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
Count: 5
+
Peek: Eve
+
Count: 5
+
Pop: Eve
+
Pop: Dave
+
Count: 3
+
True
+
False
+

          
+
Gordon
+
Fran
+
Charlie
+
Bob
+
Alice
+
}}
+

          
+
一番最後にStackに入れた要素は一番始めに取り出されるという特性上、要素を入れた順番とは逆の順番で表示されている点に注目してください。
+

          
+
***列挙操作
+
Stackでも、foreach文による列挙ができるようになっていますが、インデクサはサポートされないのでfor文による列挙は出来ません。 foreach文による列挙を行う場合は、Popしたときと同じ順で列挙されますが、当然要素の削除は行われません。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections;
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    Stack s = new Stack();
+

          
+
    s.Push("Alice");
+
    s.Push("Bob");
+
    s.Push("Charlie");
+
    s.Push("Dave");
+
    s.Push("Eve");
+

          
+
    foreach (object e in s)
+
    {
+
      Console.WriteLine(e);
+
    }
+

          
+
    Console.WriteLine("Count: {0}", s.Count);
+
    Console.WriteLine();
+

          
+
    while (0 < s.Count)
+
    {
+
      Console.WriteLine(s.Pop());
+
    }
+

          
+
    Console.WriteLine("Count: {0}", s.Count);
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim s As New Stack()
+

          
+
    s.Push("Alice")
+
    s.Push("Bob")
+
    s.Push("Charlie")
+
    s.Push("Dave")
+
    s.Push("Eve")
+

          
+
    For Each e As Object In s
+
      Console.WriteLine(e)
+
    Next
+

          
+
    Console.WriteLine("Count: {0}", s.Count)
+
    Console.WriteLine()
+

          
+
    While 0 < s.Count
+
      Console.WriteLine(s.Pop())
+
    End While
+

          
+
    Console.WriteLine("Count: {0}", s.Count)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
Eve
+
Dave
+
Charlie
+
Bob
+
Alice
+
Count: 5
+

          
+
Eve
+
Dave
+
Charlie
+
Bob
+
Alice
+
Count: 0
+
}}
+

          
+
***配列からの変換
+
配列からStackに変換するには、コンストラクタが使えます。 コンストラクタに配列を指定した場合、Stackの内容は配列の要素を先頭から一つずつPushした場合と同じ内容になります。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections;
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    string[] arr = new string[] {"Alice", "Bob", "Charlie", "Dave", "Eve"};
+
    Stack s = new Stack(arr); // 配列からStackを作成
+

          
+
    while (0 < s.Count)
+
    {
+
      Console.WriteLine(s.Pop());
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim arr() As String = New String() {"Alice", "Bob", "Charlie", "Dave", "Eve"}
+
    Dim s As New Stack(arr) ' 配列からStackを作成
+

          
+
    While 0 < s.Count
+
      Console.WriteLine(s.Pop())
+
    End While
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
Eve
+
Dave
+
Charlie
+
Bob
+
Alice
+
}}
+

          
+
***配列への変換・コピー
+
Stackから配列へ変換する場合には&msdn(netfx,method,System.Collections.Stack.ToArray){ToArrayメソッド};や&msdn(netfx,method,System.Collections.Stack.CopyTo){CopyToメソッド};が使えますが、ArrayListから配列の変換の場合とは異なり、object型の配列への変換しかサポートされていません。 変換・コピーした後の配列の内容は、Stackの内容を一つずつPopした場合と同じ内容になります。 また、変換・コピーの前後でStackの内容は変化しません。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections;
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    Stack s = new Stack();
+

          
+
    s.Push("Alice");
+
    s.Push("Bob");
+
    s.Push("Charlie");
+
    s.Push("Dave");
+
    s.Push("Eve");
+

          
+
    // 配列に変換
+
    object[] arr1 = s.ToArray();
+

          
+
    for (int i = 0; i < arr1.Length; i++)
+
    {
+
      Console.WriteLine("arr1[{0}]: {1}", i, arr1[i]);
+
    }
+

          
+
    Console.WriteLine("Count: {0}", s.Count);
+

          
+
    // 配列にコピー
+
    object[] arr2 = new object[s.Count];
+

          
+
    s.CopyTo(arr2, 0);
+

          
+
    for (int i = 0; i < arr2.Length; i++)
+
    {
+
      Console.WriteLine("arr2[{0}]: {1}", i, arr2[i]);
+
    }
+

          
+
    Console.WriteLine("Count: {0}", s.Count);
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim s As New Stack()
+

          
+
    s.Push("Alice")
+
    s.Push("Bob")
+
    s.Push("Charlie")
+
    s.Push("Dave")
+
    s.Push("Eve")
+

          
+
    ' 配列に変換
+
    Dim arr1() As Object = s.ToArray()
+

          
+
    For i As Integer = 0 To arr1.Length - 1
+
      Console.WriteLine("arr1[{0}]: {1}", i, arr1(i))
+
    Next
+

          
+
    Console.WriteLine("Count: {0}", s.Count)
+

          
+
    ' 配列にコピー
+
    Dim arr2(s.Count) As Object
+

          
+
    s.CopyTo(arr2, 0)
+

          
+
    For i As Integer = 0 To arr2.Length - 1
+
      Console.WriteLine("arr2[{0}]: {1}", i, arr2(i))
+
    Next
+

          
+
    Console.WriteLine("Count: {0}", s.Count)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
arr1[0]: Eve
+
arr1[1]: Dave
+
arr1[2]: Charlie
+
arr1[3]: Bob
+
arr1[4]: Alice
+
Count: 5
+
arr2[0]: Eve
+
arr2[1]: Dave
+
arr2[2]: Charlie
+
arr2[3]: Bob
+
arr2[4]: Alice
+
Count: 5
+
}}
+

          
+
**&aname(Queue){Queue};
+
&msdn(netfx,type,System.Collections.Queue){System.Collections.Queueクラス};は、先入れ先出し(FIFO: First-In, First-Out)のデータ構造を持つ''キュー''を提供するコレクションクラスです。 (Queueクラスに相当するジェネリックなコレクションクラスは、[[System.Collections.Generic.Queue>#Generic.Queue]]クラスです)
+

          
+
***基本的な操作
+
#ref(01.png,キュー)
+
.NET FrameworkにおけるQueueクラスの概要を見ていきます。 Queueに要素を追加する''エンキュー''の操作は&msdn(netfx,method,System.Collections.Queue.Enqueue){Enqueueメソッド};、Queueから要素を取り出す''デキュー''の操作は&msdn(netfx,method,System.Collections.Queue.Dequeue){Dequeueメソッド};で行います。 Queueから要素を''デキュー''すると、取り出した要素はQueueから削除されます。 待ち行列の最後尾に一人並べる作業が''エンキュー''、待ち行列の先頭から一人引き抜く作業が''デキュー''に相当するとイメージするとよいと思います。
+

          
+
また、&msdn(netfx,method,System.Collections.Queue.Peek){Peekメソッド};を使うと、Queueの内容はそのままで(削除されずに)先頭にある要素を取得できます。 Queueの内容が空の場合に、DequeueメソッドやPeekメソッドを呼び出すとInvalidOperationExceptionがスローされます。 Queueの内容を空にするには、&msdn(netfx,method,System.Collections.Queue.Clear){Clearメソッド};を使います。 Queueに指定した内容の要素が含まれているか調べるには、&msdn(netfx,method,System.Collections.Queue.Contains){Containsメソッド};を使います。
+

          
+
Queueに現在いくつの要素が含まれているかを知るには&msdn(netfx,member,System.Collections.Queue.Count){Countプロパティ};を参照します。 ArrayListなどと同様、Queueには任意の数の要素をエンキューできます。 Queue内部の容量はエンキューの際に自動的に拡充されます。 デキューの際に要素数が減っても、Queue内部で確保されている容量は減ることはありません。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections;
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    Queue q = new Queue();
+

          
+
    // Queueに要素をEnqueue
+
    q.Enqueue("Alice");
+
    q.Enqueue("Bob");
+
    q.Enqueue("Charlie");
+
    q.Enqueue("Dave");
+
    q.Enqueue("Eve");
+

          
+
    Console.WriteLine("Count: {0}", q.Count);
+

          
+
    // Queueの先頭にある要素をPeek
+
    Console.WriteLine("Peek: {0}", q.Peek());
+

          
+
    Console.WriteLine("Count: {0}", q.Count);
+

          
+
    // Queueの先頭にある要素をDequeue
+
    Console.WriteLine("Dequeue: {0}", q.Dequeue());
+
    Console.WriteLine("Dequeue: {0}", q.Dequeue());
+

          
+
    Console.WriteLine("Count: {0}", q.Count);
+

          
+
    // Queueに"Alice", "Eve"が含まれるか調べる
+
    Console.WriteLine(q.Contains("Alice"));
+
    Console.WriteLine(q.Contains("Eve"));
+

          
+
    // Queueに"Fran", "Gordon"をEnqueue
+
    q.Enqueue("Fran");
+
    q.Enqueue("Gordon");
+

          
+
    Console.WriteLine();
+

          
+
    // Queueが空になるまで内容をDequeue
+
    while (0 < q.Count)
+
    {
+
      Console.WriteLine(q.Dequeue());
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim q As New Queue()
+

          
+
    ' Queueに要素をEnqueue
+
    q.Enqueue("Alice")
+
    q.Enqueue("Bob")
+
    q.Enqueue("Charlie")
+
    q.Enqueue("Dave")
+
    q.Enqueue("Eve")
+

          
+
    Console.WriteLine("Count: {0}", q.Count)
+

          
+
    ' Queueの先頭にある要素をPeek
+
    Console.WriteLine("Peek: {0}", q.Peek())
+

          
+
    Console.WriteLine("Count: {0}", q.Count)
+

          
+
    ' Queueの先頭にある要素をDequeue
+
    Console.WriteLine("Dequeue: {0}", q.Dequeue())
+
    Console.WriteLine("Dequeue: {0}", q.Dequeue())
+

          
+
    Console.WriteLine("Count: {0}", q.Count)
+

          
+
    ' Queueに"Alice", "Eve"が含まれるか調べる
+
    Console.WriteLine(q.Contains("Alice"))
+
    Console.WriteLine(q.Contains("Eve"))
+

          
+
    ' Queueに"Fran", "Gordon"をEnqueue
+
    q.Enqueue("Fran")
+
    q.Enqueue("Gordon")
+

          
+
    Console.WriteLine()
+

          
+
    ' Queueが空になるまで内容をDequeue
+
    While 0 < q.Count
+
      Console.WriteLine(q.Dequeue())
+
    End While
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
Count: 5
+
Peek: Alice
+
Count: 5
+
Dequeue: Alice
+
Dequeue: Bob
+
Count: 3
+
False
+
True
+

          
+
Charlie
+
Dave
+
Eve
+
Fran
+
Gordon
+
}}
+

          
+
一番最初にStackに入れた要素は一番始めに取り出されるという特性上、要素を入れた順番と同じ順番で表示されている点に注目してください。
+

          
+
***列挙操作
+
Queueでも、foreach文による列挙ができるようになっていますが、インデクサはサポートされないのでfor文による列挙は出来ません。 foreach文による列挙を行う場合は、Dequeueしたときと同じ順で列挙されますが、当然要素の削除は行われません。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections;
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    Queue q = new Queue();
+

          
+
    q.Enqueue("Alice");
+
    q.Enqueue("Bob");
+
    q.Enqueue("Charlie");
+
    q.Enqueue("Dave");
+
    q.Enqueue("Eve");
+

          
+
    foreach (object e in q)
+
    {
+
      Console.WriteLine(e);
+
    }
+

          
+
    Console.WriteLine("Count: {0}", q.Count);
+
    Console.WriteLine();
+

          
+
    while (0 < q.Count)
+
    {
+
      Console.WriteLine(q.Dequeue());
+
    }
+

          
+
    Console.WriteLine("Count: {0}", q.Count);
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim q As New Queue()
+

          
+
    q.Enqueue("Alice")
+
    q.Enqueue("Bob")
+
    q.Enqueue("Charlie")
+
    q.Enqueue("Dave")
+
    q.Enqueue("Eve")
+

          
+

          
+
    For Each e As Object In q
+
      Console.WriteLine(e)
+
    Next
+

          
+
    Console.WriteLine("Count: {0}", q.Count)
+
    Console.WriteLine()
+

          
+
    While 0 < q.Count
+
      Console.WriteLine(q.Dequeue())
+
    End While
+

          
+
    Console.WriteLine("Count: {0}", q.Count)
+

          
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
Alice
+
Bob
+
Charlie
+
Dave
+
Eve
+
Count: 5
+

          
+
Alice
+
Bob
+
Charlie
+
Dave
+
Eve
+
Count: 0
+
}}
+

          
+
***配列からの変換
+
配列からQueueに変換するには、コンストラクタが使えます。 コンストラクタに配列を指定した場合、Queueの内容は配列の要素を先頭から一つずつEnqueueした場合と同じ内容になります。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections;
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    string[] arr = new string[] {"Alice", "Bob", "Charlie", "Dave", "Eve"};
+
    Queue q = new Queue(arr); // 配列からQueueを作成
+

          
+
    while (0 < q.Count)
+
    {
+
      Console.WriteLine(q.Dequeue());
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim arr() As String = New String() {"Alice", "Bob", "Charlie", "Dave", "Eve"}
+
    Dim q As New Queue(arr) ' 配列からQueueを作成
+

          
+
    While 0 < q.Count
+
      Console.WriteLine(q.Dequeue())
+
    End While
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
Alice
+
Bob
+
Charlie
+
Dave
+
Eve
+
}}
+

          
+
***配列への変換・コピー
+
Queueから配列へ変換する場合には&msdn(netfx,method,System.Collections.Queue.ToArray){ToArrayメソッド};や&msdn(netfx,method,System.Collections.Queue.CopyTo){CopyToメソッド};が使えますが、ArrayListから配列の変換の場合とは異なり、object型の配列への変換しかサポートされていません。 変換・コピーした後の配列の内容は、Queueの内容を一つずつDequeueした場合と同じ内容になります。 また、変換・コピーの前後でQueueの内容は変化しません。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections;
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    Queue q = new Queue();
+

          
+
    q.Enqueue("Alice");
+
    q.Enqueue("Bob");
+
    q.Enqueue("Charlie");
+
    q.Enqueue("Dave");
+
    q.Enqueue("Eve");
+

          
+
    // 配列に変換
+
    object[] arr1 = q.ToArray();
+

          
+
    for (int i = 0; i < arr1.Length; i++)
+
    {
+
      Console.WriteLine("arr1[{0}]: {1}", i, arr1[i]);
+
    }
+

          
+
    Console.WriteLine("Count: {0}", q.Count);
+

          
+
    // 配列にコピー
+
    object[] arr2 = new object[q.Count];
+

          
+
    q.CopyTo(arr2, 0);
+

          
+
    for (int i = 0; i < arr2.Length; i++)
+
    {
+
      Console.WriteLine("arr2[{0}]: {1}", i, arr2[i]);
+
    }
+

          
+
    Console.WriteLine("Count: {0}", q.Count);
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim q As New Queue()
+

          
+
    q.Enqueue("Alice")
+
    q.Enqueue("Bob")
+
    q.Enqueue("Charlie")
+
    q.Enqueue("Dave")
+
    q.Enqueue("Eve")
+

          
+
    ' 配列に変換
+
    Dim arr1() As Object = q.ToArray()
+

          
+
    For i As Integer = 0 To arr1.Length - 1
+
      Console.WriteLine("arr1[{0}]: {1}", i, arr1(i))
+
    Next
+

          
+
    Console.WriteLine("Count: {0}", q.Count)
+

          
+
    ' 配列にコピー
+
    Dim arr2(q.Count) As Object
+

          
+
    q.CopyTo(arr2, 0)
+

          
+
    For i As Integer = 0 To arr2.Length - 1
+
      Console.WriteLine("arr2[{0}]: {1}", i, arr2(i))
+
    Next
+

          
+
    Console.WriteLine("Count: {0}", q.Count)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
arr1[0]: Alice
+
arr1[1]: Bob
+
arr1[2]: Charlie
+
arr1[3]: Dave
+
arr1[4]: Eve
+
Count: 5
+
arr2[0]: Alice
+
arr2[1]: Bob
+
arr2[2]: Charlie
+
arr2[3]: Dave
+
arr2[4]: Eve
+
Count: 5
+
}}
+

          
+
**&aname(CollectionBase){CollectionBase};
+
&msdn(netfx,type,System.Collections.CollectionBase){System.Collections.CollectionBaseクラス};は、独自にコレクションクラスを実装するのに便利な抽象クラスです。 コレクションに要素を追加・挿入・削除・設定する際の動作をオーバーライドすることができます。 (CollectionBaseクラスに相当するジェネリックなコレクションクラスは、[[System.Collections.ObjectModel.Collection>#ObjectModel.Collection]]クラスです)
+

          
+
CollectionBaseクラスを継承して、挿入される要素の型をチェックするようにすればジェネリックコレクションのように厳密に型指定されたコレクションを作ることが可能です。 また、コレクションの内容が変更されたときにイベントを発生させてクラス外に通知する、といったことも可能になります。
+

          
+
CollectionBaseクラスでは内部にArrayListを持っていて、これがコレクションとしての実体となります。 派生クラスからは、&msdn(netfx,member,System.Collections.CollectionBase.List){Listプロパティ};を通してアクセスします。 また、CollectionBaseクラスでは、次のプロテクトメソッドをオーバーライドすることが出来ます。
+

          
+
|*オーバーライド可能なメソッド
+
|~メソッド|~メソッドが呼ばれるタイミング|h
+
|&msdn(netfx,method,System.Collections.CollectionBase.OnValidate){OnValidate};|内部コレクションに要素を追加・設定しようとしたとき&br;OnSet, OnInsert, OnRemoveの各メソッドが呼ばれる前に呼び出されます|
+
|&msdn(netfx,method,System.Collections.CollectionBase.OnSet){OnSet};|内部コレクションの要素を設定しようとしたとき|
+
|&msdn(netfx,method,System.Collections.CollectionBase.OnInsert){OnInsert};|内部コレクションに要素を挿入しようとしたとき|
+
|&msdn(netfx,method,System.Collections.CollectionBase.OnRemove){OnRemove};|内部コレクションから要素を削除しようとしたとき|
+
|&msdn(netfx,method,System.Collections.CollectionBase.OnClear){OnClear};|内部コレクションから全要素を削除しようとしたとき|
+
|&msdn(netfx,method,System.Collections.CollectionBase.OnSetComplete){OnSetComplete};|内部コレクションへの要素の設定が完了したとき|
+
|&msdn(netfx,method,System.Collections.CollectionBase.OnInsertComplete){OnInsertComplete};|内部コレクションへの要素の挿入が完了したとき|
+
|&msdn(netfx,method,System.Collections.CollectionBase.OnRemoveComplete){OnRemoveComplete};|内部コレクションからの要素の削除が完了したとき|
+
|&msdn(netfx,method,System.Collections.CollectionBase.OnClearComplete){OnClearComplete};|内部コレクションからの全要素の削除が完了したとき|
+

          
+
これらのメソッドは、派生クラスからListプロパティを通して内部コレクションにアクセスした場合と、クラス外からIListインターフェイスを経由してアクセスされた場合に呼び出されます。 派生クラスから内部コレクションにアクセスする方法としてもう一つ&msdn(netfx,member,System.Collections.CollectionBase.InnerList){InnerListプロパティ};も用意されていますが、このプロパティを通して直接内部コレクションの実体にアクセスした場合は、これらのメソッドは呼び出されません。
+

          
+
また、Add, Insert, Remove, ContainsなどのメソッドはCollectionBaseクラスでは提供されないため、派生クラスにて内部コレクションへの追加・削除・挿入を行うメソッドを用意する必要があります。
+

          
+
***実装例
+
以下は、CollectionBaseを継承し、OnValidateメソッドをオーバーライドしてString型の値のみをコレクションに追加できるStringCollectionクラスを実装する例です。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections;
+

          
+
class StringCollection : CollectionBase
+
{
+
  public void Add(string s)
+
  {
+
    // 型チェックの必要は無いので、直接内部コレクションに追加する
+
    InnerList.Add(s);
+
  }
+

          
+
  protected override void OnValidate(object val)
+
  {
+
    if (val != null && val.GetType() != typeof(string))
+
      // valの型がstring以外の場合、ArgumentExceptionをスローする
+
      throw new ArgumentException("String型以外はコレクションに追加できません");
+
  }
+
}
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    StringCollection sc = new StringCollection();
+

          
+
    // 独自に実装したAddメソッドで要素を追加
+
    sc.Add("foo");
+

          
+
    // IListインターフェイスに変換し、IList.Addメソッドで要素を追加
+
    IList l = sc;
+

          
+
    l.Add("bar");
+

          
+
    foreach (string s in sc)
+
    {
+
      Console.WriteLine(s);
+
    }
+

          
+
    try
+
    {
+
      // IList.Addメソッドはobjectを引数にとるので数値を追加しようとしても
+
      // コンパイルエラーにはならないが、追加の際にOnValidateメソッドが
+
      // 呼び出されるため、ArgumentExceptionがスローされる
+
      l.Add(16);
+
    }
+
    catch (ArgumentException ex)
+
    {
+
      Console.WriteLine(ex.Message);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections
+

          
+
Class StringCollection
+
  Inherits CollectionBase
+

          
+
  Public Sub Add(ByVal s As String)
+
    ' 型チェックの必要は無いので、直接内部コレクションに追加する
+
    InnerList.Add(s)
+
  End Sub
+

          
+
  Protected Overrides Sub OnValidate(ByVal val As Object)
+
    If (Not val Is Nothing) AndAlso (Not val.GetType() Is GetType(String)) Then
+
      ' valの型がstring以外の場合、ArgumentExceptionをスローする
+
      Throw New ArgumentException("String型以外はコレクションに追加できません")
+
    End If
+
  End Sub
+
End Class
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim sc As New StringCollection()
+

          
+
    ' 独自に実装したAddメソッドで要素を追加
+
    sc.Add("foo")
+

          
+
    ' IListインターフェイスに変換し、IList.Addメソッドで要素を追加
+
    Dim l As IList = sc
+

          
+
    l.Add("bar")
+

          
+
    For Each s As String In sc
+
      Console.WriteLine(s)
+
    Next
+

          
+
    Try
+
      ' IList.AddメソッドはObjectを引数にとるので数値を追加しようとしても
+
      ' コンパイルエラーにはならないが、追加の際にOnValidateメソッドが
+
      ' 呼び出されるため、ArgumentExceptionがスローされる
+
      l.Add(16)
+
    Catch ex As ArgumentException
+
      Console.WriteLine(ex.Message)
+
    End Try
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
foo
+
bar
+
String型以外はコレクションに追加できません
+
}}
+

          
+
以下は、CollectionBaseを継承し、Integer型の値のみを追加できるスタックIntStackを実装する例です。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections;
+

          
+
class IntStack : CollectionBase
+
{
+
  public void Push(int i)
+
  {
+
    InnerList.Insert(InnerList.Count, i);
+
  }
+

          
+
  public int Pop()
+
  {
+
    int headIndex = InnerList.Count - 1;
+

          
+
    if (headIndex == -1) throw new InvalidOperationException("IntStackは空です");
+

          
+
    int val = (int)InnerList[headIndex];
+

          
+
    InnerList.RemoveAt(headIndex);
+

          
+
    return val;
+
  }
+

          
+
  public int Peek()
+
  {
+
    int headIndex = InnerList.Count - 1;
+

          
+
    if (headIndex == -1) throw new InvalidOperationException("IntStackは空です");
+

          
+
    return (int)InnerList[headIndex];
+
  }
+

          
+
  protected override void OnValidate(object val)
+
  {
+
    if (val != null && val.GetType() != typeof(int))
+
      // valの型がint以外の場合、ArgumentExceptionをスローする
+
      throw new ArgumentException("Integer型以外はコレクションに追加できません");
+
  }
+
}
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    IntStack s = new IntStack();
+
    //Stack s = new Stack();
+

          
+
    s.Push(0);
+
    s.Push(1);
+
    s.Push(2);
+
    s.Push(3);
+
    s.Push(4);
+

          
+
    // Stackの先頭にある要素をPeek
+
    Console.WriteLine("Peek: {0}", s.Peek());
+

          
+
    // Stackの先頭にある要素をPop
+
    Console.WriteLine("Pop: {0}", s.Pop());
+
    Console.WriteLine("Pop: {0}", s.Pop());
+

          
+
    s.Push(5);
+
    s.Push(6);
+

          
+
    // Stackが空になるまで内容をPop
+
    while (0 < s.Count)
+
    {
+
      Console.WriteLine(s.Pop());
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections
+

          
+
Class IntStack
+
  Inherits CollectionBase
+

          
+
  Public Sub Push(ByVal i As Integer)
+
    InnerList.Insert(InnerList.Count, i)
+
  End Sub
+

          
+
  Public Function Pop() As Integer
+
    Dim headIndex As Integer = InnerList.Count - 1
+

          
+
    If headIndex = -1 Then Throw New InvalidOperationException("IntStackは空です")
+

          
+
    Dim val As Integer = CInt(InnerList(headIndex))
+

          
+
    InnerList.RemoveAt(headIndex)
+

          
+
    Return val
+
  End Function
+

          
+
  Public Function Peek() As Integer
+
    Dim headIndex As Integer = InnerList.Count - 1
+

          
+
    If headIndex = -1 Then Throw New InvalidOperationException("IntStackは空です")
+

          
+
    Return CInt(InnerList(headIndex))
+
  End Function
+

          
+
  Protected Overrides Sub OnValidate(ByVal val As Object)
+
    If (Not val Is Nothing) AndAlso (Not val.GetType() Is GetType(Integer)) Then
+
      ' valの型がInteger以外の場合、ArgumentExceptionをスローする
+
      Throw New ArgumentException("Integer型以外はコレクションに追加できません")
+
    End If
+
  End Sub
+
End Class
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim s As New IntStack()
+
    'Dim s As New Stack()
+

          
+
    s.Push(0)
+
    s.Push(1)
+
    s.Push(2)
+
    s.Push(3)
+
    s.Push(4)
+

          
+
    ' Stackの先頭にある要素をPeek
+
    Console.WriteLine("Peek: {0}", s.Peek())
+

          
+
    ' Stackの先頭にある要素をPop
+
    Console.WriteLine("Pop: {0}", s.Pop())
+
    Console.WriteLine("Pop: {0}", s.Pop())
+

          
+
    s.Push(5)
+
    s.Push(6)
+

          
+
    ' Stackが空になるまで内容をPop
+
    While 0 < s.Count
+
      Console.WriteLine(s.Pop())
+
    End While
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
Peek: 4
+
Pop: 4
+
Pop: 3
+
6
+
5
+
2
+
1
+
0
+
}}
+

          
+
----
+

          
+
*&aname(GenericCollections){ジェネリックコレクション (System.Collections.Generic)};
+
ここでは&msdn(netfx,ns,System.Collections.Generic){System.Collections.Generic名前空間};にある、ジェネリックなコレクションを見ていきます。 非ジェネリックコレクションとジェネリックコレクションの大きな違いは、主に
+
+厳密に型定義されている (タイプセーフである)
+
+objectへのキャストが行われない (値型の場合はボックス化/ボックス化解除が発生しない)
+

          
+
の2点です。 System.Collections.Generic名前空間には、System.Collections名前空間で提供される非ジェネリックコレクションから機能が強化されたジェネリックコレクションが用意されています。 ここではジェネリックコレクションで使用できる操作を中心に解説するので、基本的な操作については必要に応じて[[非ジェネリックコレクション>#NonGenericCollections]]の解説を参照してください。
+

          
+
**&aname(Generic.List){List};
+
&msdn(netfx,id,6sh2ey19){System.Collections.Generic.Listクラス};は[[System.Collections.ArrayList>#ArrayList]]に相当するジェネリックコレクションです。 基本的な操作は、ArrayListと同じです。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    List<int> list = new List<int>();
+

          
+
    // 要素の追加
+
    list.Add(0);
+
    list.Add(1);
+
    list.Add(2);
+

          
+
    Print(list);
+

          
+
    // 複数の要素の追加
+
    list.AddRange(new int[] {3, 4, 5, 6});
+

          
+
    Print(list);
+

          
+
    // 要素の削除
+
    list.Remove(3);
+
    list.Remove(6);
+

          
+
    Print(list);
+

          
+
    // 特定の位置にある要素を削除
+
    list.RemoveAt(0);
+

          
+
    Print(list);
+

          
+
    // 特定の位置にある要素を変更
+
    list[2] = 7;
+

          
+
    Print(list);
+

          
+
    // 特定の位置に要素を挿入
+
    list.Insert(2, 3);
+

          
+
    Print(list);
+

          
+
    // Listの内容をソート
+
    list.Sort();
+

          
+
    Print(list);
+

          
+
    // Listの内容を反転
+
    list.Reverse();
+

          
+
    Print(list);
+
  }
+

          
+
  static void Print(List<int> list)
+
  {
+
    foreach (int e in list)
+
    {
+
      Console.Write("{0}, ", e);
+
    }
+

          
+
    Console.WriteLine();
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim list As New List(Of Integer)()
+

          
+
    ' 要素の追加
+
    list.Add(0)
+
    list.Add(1)
+
    list.Add(2)
+

          
+
    Print(list)
+

          
+
    ' 複数の要素の追加
+
    list.AddRange(New Integer() {3, 4, 5, 6})
+

          
+
    Print(list)
+

          
+
    ' 要素の削除
+
    list.Remove(3)
+
    list.Remove(6)
+

          
+
    Print(list)
+

          
+
    ' 特定の位置にある要素を削除
+
    list.RemoveAt(0)
+

          
+
    Print(list)
+

          
+
    ' 特定の位置にある要素を変更
+
    list(2) = 7
+

          
+
    Print(list)
+

          
+
    ' 特定の位置に要素を挿入
+
    list.Insert(2, 3)
+

          
+
    Print(list)
+

          
+
    ' Listの内容をソート
+
    list.Sort()
+

          
+
    Print(list)
+

          
+
    ' Listの内容を反転
+
    list.Reverse()
+

          
+
    Print(list)
+
  End Sub
+

          
+
  Shared Sub Print(ByVal list As List(Of Integer))
+
    For Each e As Integer In list
+
      Console.Write("{0}, ", e)
+
    Next
+

          
+
    Console.WriteLine()
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
0, 1, 2, 
+
0, 1, 2, 3, 4, 5, 6, 
+
0, 1, 2, 4, 5, 
+
1, 2, 4, 5, 
+
1, 2, 7, 5, 
+
1, 2, 3, 7, 5, 
+
1, 2, 3, 5, 7, 
+
7, 5, 3, 2, 1, 
+
}}
+

          
+
ただ、単にジェネリックなArrayListというわけではなく、ArrayListと比べるとより高度な操作が可能になっています。
+

          
+
***述語(Predicate)を用いた検索
+
Listクラスでは、述語(Predicateデリゲート)を用いた検索・一致の検証が行えます。 条件式を記述したメソッドを一種の引数として渡すことで、その条件に合致する要素が存在するかどうか、といった操作が出きるようになります。 例えば、Containsメソッドでは引数で指定した要素が含まれているかどうかは調べられますが、''どのような''要素が含まれているかという''条件''を指定することは出来ません。 対してExistsメソッドでは、「文字列の長さが5以上の」や「数値の大きさが16未満の」といった条件を指定した上で、それに合致する要素が含まれているかどうかを調べることが出来ます。
+

          
+
Listクラスの次のメソッドでは、Predicateデリゲートを引数として渡すことで、述語で記述した条件にあう要素の検索などが行えます。
+

          
+
|*Listクラスのメソッド
+
|~メソッド|~動作|h
+
|&msdn(netfx,id,x0b5b5bc){Find};|述語で記述した条件に合致する最初の要素を取得する|
+
|&msdn(netfx,id,5kthb929){FindLast};|述語で記述した条件に合致する最後の要素を取得する|
+
|&msdn(netfx,id,fh1w7y8z){FindAll};|述語で記述した条件に合致するすべての要素をListで取得する|
+
|&msdn(netfx,id,x1xzf2ca){FindIndex};|述語で記述した条件に合致する最初の要素のインデックスを取得する|
+
|&msdn(netfx,id,xzs5503w){FindLastIndex};|述語で記述した条件に合致する最後の要素のインデックスを取得する|
+
|&msdn(netfx,id,bfed8bca){Exists};|述語で記述した条件に合致する要素が存在するかどうか調べる|
+
|&msdn(netfx,id,wdka673a){RemoveAll};|述語で記述した条件に合致する要素を削除する|
+
|&msdn(netfx,id,kdxe4x4w){TrueForAll};|述語で記述した条件に、すべての要素が合致するかどうか調べる|
+

          
+
以下は、これらのメソッドを使った例です。
+

          
+
#tabpage(C# 2.0)
+
#code(cs){{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    List<string> list = new List<string>() {"Alice", "Bob", "Charlie", "Dave", "Eve"};
+

          
+
    // 長さが5以上の要素が存在するかどうか
+
    Console.WriteLine("Exists: {0}", list.Exists(delegate(string s)
+
    {
+
      return 5 <= s.Length;
+
    }));
+

          
+
    // 長さが3である最初の要素
+
    Console.WriteLine("Find: {0}", list.Find(delegate(string s)
+
    {
+
      return s.Length == 3;
+
    }));
+

          
+
    // 長さが3である最後の要素
+
    Console.WriteLine("FindLast: {0}", list.FindLast(delegate(string s)
+
    {
+
      return s.Length == 3;
+
    }));
+

          
+
    // すべての要素が"e"で終わるかどうか
+
    Console.WriteLine("TrueForAll: {0}", list.TrueForAll(delegate(string s)
+
    {
+
      return s.EndsWith("e");
+
    }));
+

          
+
    // すべての要素の長さが10未満かどうか
+
    Console.WriteLine("TrueForAll: {0}", list.TrueForAll(delegate(string s)
+
    {
+
      return s.Length < 10;
+
    }));
+

          
+
    // "li"を含む要素を削除
+
    list.RemoveAll(delegate(string s)
+
    {
+
      return s.Contains("li");
+
    });
+

          
+
    Console.WriteLine("RemoveAll");
+

          
+
    foreach (string e in list)
+
    {
+
      Console.WriteLine(e);
+
    }
+
  }
+
}
+
}}
+
#tabpage(C# 3.0)
+
#code(cs){{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    List<string> list = new List<string>() {"Alice", "Bob", "Charlie", "Dave", "Eve"};
+

          
+
    // 長さが5以上の要素が存在するかどうか
+
    Console.WriteLine("Exists: {0}", list.Exists(s => 5 <= s.Length));
+

          
+
    // 長さが3である最初の要素
+
    Console.WriteLine("Find: {0}", list.Find(s => s.Length == 3));
+

          
+
    // 長さが3である最後の要素
+
    Console.WriteLine("FindLast: {0}", list.FindLast(s => s.Length == 3));
+

          
+
    // すべての要素が"e"で終わるかどうか
+
    Console.WriteLine("TrueForAll: {0}", list.TrueForAll(s => s.EndsWith("e")));
+

          
+
    // すべての要素の長さが10未満かどうか
+
    Console.WriteLine("TrueForAll: {0}", list.TrueForAll(s => s.Length < 10));
+

          
+
    // "li"を含む要素を削除
+
    list.RemoveAll(s => s.Contains("li"));
+

          
+
    Console.WriteLine("RemoveAll");
+

          
+
    foreach (string e in list)
+
    {
+
      Console.WriteLine(e);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB10)
+
#code(vb){{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim list As New List(Of String)(New String() {"Alice", "Bob", "Charlie", "Dave", "Eve"})
+

          
+
    ' 長さが5以上の要素が存在するかどうか
+
    Console.WriteLine("Exists: {0}", list.Exists(Function(s) 5 <= s.Length))
+

          
+
    ' 長さが3である最初の要素
+
    Console.WriteLine("Find: {0}", list.Find(Function(s) s.Length = 3))
+

          
+
    ' 長さが3である最後の要素
+
    Console.WriteLine("FindLast: {0}", list.FindLast(Function(s) s.Length = 3))
+

          
+
    ' すべての要素が"e"で終わるかどうか
+
    Console.WriteLine("TrueForAll: {0}", list.TrueForAll(Function(s) s.EndsWith("e")))
+

          
+
    ' すべての要素の長さが10未満かどうか
+
    Console.WriteLine("TrueForAll: {0}", list.TrueForAll(Function(s) s.Length < 10))
+

          
+
    ' "li"を含む要素を削除
+
    list.RemoveAll(Function(s) s.Contains("li"))
+

          
+
    Console.WriteLine("RemoveAll")
+

          
+
    For Each e As String In list
+
      Console.WriteLine(e)
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
Exists: True
+
Find: Bob
+
FindLast: Eve
+
TrueForAll: False
+
TrueForAll: True
+
RemoveAll
+
Bob
+
Dave
+
Eve
+
}}
+

          
+
***列挙操作
+
Listクラスでは、foreach文による列挙の他に、&msdn(netfx,id,bwabdf9z){ForEachメソッド};による列挙が出来るようになっています。 このメソッドは、引数に列挙時に個々の要素に対して行う操作を指定します。
+

          
+
#tabpage(C# 2.0)
+
#code(cs){{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    List<string> list = new List<string>() {"Alice", "Bob", "Charlie", "Dave", "Eve"};
+

          
+
    // foreach文による列挙
+
    Console.WriteLine("[foreach]");
+

          
+
    foreach (string e in list)
+
    {
+
      Console.WriteLine(e);
+
    }
+

          
+
    // ForEachメソッドによる列挙
+
    Console.WriteLine("[ForEach]");
+

          
+
    list.ForEach(delegate(string e)
+
    {
+
      Console.WriteLine(e);
+
    });
+
  }
+
}
+
}}
+
#tabpage(C# 3.0)
+
#code(cs){{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    List<string> list = new List<string>() {"Alice", "Bob", "Charlie", "Dave", "Eve"};
+

          
+
    // foreach文による列挙
+
    Console.WriteLine("[foreach]");
+

          
+
    foreach (string e in list)
+
    {
+
      Console.WriteLine(e);
+
    }
+

          
+
    // ForEachメソッドによる列挙
+
    Console.WriteLine("[ForEach]");
+

          
+
    list.ForEach(e => Console.WriteLine(e));
+
  }
+
}
+
}}
+
#tabpage(VB10)
+
#code(vb){{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim list As New List(Of String)(New String() {"Alice", "Bob", "Charlie", "Dave", "Eve"})
+

          
+
    ' For Eachステートメントによる列挙
+
    Console.WriteLine("[For Each statement]")
+

          
+
    For Each e As String In list
+
      Console.WriteLine(e)
+
    Next
+

          
+
    ' ForEachメソッドによる列挙
+
    Console.WriteLine("[ForEach]")
+

          
+
    list.ForEach(Sub(e) Console.WriteLine(e))
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
[foreach]
+
Alice
+
Bob
+
Charlie
+
Dave
+
Eve
+
[ForEach]
+
Alice
+
Bob
+
Charlie
+
Dave
+
Eve
+
}}
+

          
+
***型変換
+
&msdn(netfx,id,73fe8cwf){ConvertAllメソッド};を使うと、要素のすべてを別の型に変換出来ます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    List<string> stringList = new List<string>() {"0", "1", "2", "3", "4"};
+

          
+
    List<int> intList = stringList.ConvertAll(int.Parse);
+

          
+
    foreach (int e in intList)
+
    {
+
      Console.WriteLine(e);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim stringList As New List(Of String)(New String() {"0", "1", "2", "3", "4"})
+

          
+
    Dim intList As List(Of Integer) = stringList.ConvertAll(AddressOf Integer.Parse)
+

          
+
    For Each e As Integer In intList
+
      Console.WriteLine(e)
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
0
+
1
+
2
+
3
+
4
+
}}
+

          
+
また、単なる型変換だけでなく、すべての要素に同じ処理を施した結果を取得するといった方法にも使えます。
+

          
+
#tabpage(C# 2.0)
+
#code(cs){{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    List<string> list = new List<string>() {"Alice", "Bob", "Charlie", "Dave", "Eve"};
+

          
+
    List<string> reversedList = list.ConvertAll(delegate(string s)
+
    {
+
      // 文字列をリバースする
+
      char[] chars = s.ToCharArray();
+

          
+
      Array.Reverse(chars);
+

          
+
      return new string(chars);
+
    });
+

          
+
    foreach (string e in reversedList)
+
    {
+
      Console.WriteLine(e);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB10)
+
#code(vb){{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim list As New List(Of String)(New String() {"Alice", "Bob", "Charlie", "Dave", "Eve"})
+

          
+
    Dim reversedList As List(Of String) = list.ConvertAll(Function(s)
+
      ' 文字列をリバースする
+
      Dim chars() As Char = s.ToCharArray()
+

          
+
      Array.Reverse(chars)
+

          
+
      Return New String(chars)
+
    End Function)
+

          
+
    For Each e As String In reversedList
+
      Console.WriteLine(e)
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
ecilA
+
boB
+
eilrahC
+
evaD
+
evE
+
}}
+

          
+
**&aname(Generic.Dictionary){Dictionary};
+
&msdn(netfx,id,xfhwa508){System.Collections.Generic.Dictionaryクラス};は[[System.Collections.Hashtable>#Hashtable]]に相当するジェネリックコレクションです。 基本的な操作はHashtableと同じですが、キーに該当する要素がない場合の動作が異なります。 Hashtableではキーに該当する要素がない場合はnull(Nothing)が返されますが、DictionaryではKeyNotFoundExceptionがスローされます。 Hashtableではキーがないことを表すnullなのかキーに該当する値がnullなのか区別することが出来ませんが、これによりDictionaryではキーが設定されていない場合と値としてnullが設定されている場合を区別できるようになっています。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    Dictionary<string, int> dict = new Dictionary<string, int>();
+

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

          
+
    dict["bar"] = 72; // キー"bar"の値として値72を設定
+
    dict["baz"] = 42; // キー"baz"の値として値42を設定
+

          
+
    Console.WriteLine(dict["foo"]); // キー"foo"の値を取得
+
    Console.WriteLine(dict["bar"]); // キー"bar"の値を取得
+
    Console.WriteLine(dict["baz"]); // キー"baz"の値を取得
+

          
+
    // キーに該当する要素がない場合は、KeyNotFoundExceptionがスローされる
+
    try
+
    {
+
      Console.WriteLine(dict["hoge"]);
+
    }
+
    catch (KeyNotFoundException)
+
    {
+
      Console.WriteLine("KeyNotFoundException");
+
    }
+

          
+
    Console.WriteLine(dict.Count); // 現在のキーと値の対の数を取得
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim dict As New Dictionary(Of String, Integer)
+

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

          
+
    dict("bar") = 72 ' キー"bar"の値として値72を設定
+
    dict("baz") = 42 ' キー"baz"の値として値42を設定
+

          
+
    Console.WriteLine(dict("foo")) ' キー"foo"の値を取得
+
    Console.WriteLine(dict("bar")) ' キー"bar"の値を取得
+
    Console.WriteLine(dict("baz")) ' キー"baz"の値を取得
+

          
+
    ' キーに該当する要素がない場合は、KeyNotFoundExceptionがスローされる
+
    Try
+
      Console.WriteLine(dict("hoge"))
+
    Catch ex As KeyNotFoundException
+
      Console.WriteLine("KeyNotFoundException")
+
    End Try
+

          
+
    Console.WriteLine(dict.Count) ' 現在のキーと値の対の数を取得
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
16
+
72
+
42
+
KeyNotFoundException
+
3
+
}}
+

          
+
***列挙操作
+
Hashtableと同様、Dictionaryもforeach文によって要素を列挙することができますが、個々のペアはDictionaryEntry構造体ではなく&msdn(netfx,id,5tbh8a42){KeyValuePair構造体};で格納されます。 また、すべてのキーはKeysプロパティ、値はValuesプロパティを通して参照できます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    Dictionary<string, int> dict = new Dictionary<string, int>();
+

          
+
    dict["foo"] = 16;
+
    dict["bar"] = 72;
+
    dict["baz"] = 42;
+

          
+
    // Dictionaryに格納されているキーと値のペアを列挙
+
    foreach (KeyValuePair<string, int> entry in dict)
+
    {
+
      Console.WriteLine("{0} => {1}", entry.Key, entry.Value);
+
    }
+

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

          
+
    foreach (string key in dict.Keys)
+
    {
+
      Console.WriteLine(key);
+
    }
+

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

          
+
    foreach (int val in dict.Values)
+
    {
+
      Console.WriteLine(val);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim dict As New Dictionary(Of String, Integer)()
+

          
+
    dict("foo") = 16
+
    dict("bar") = 72
+
    dict("baz") = 42
+

          
+
    ' Dictionaryに格納されているキーと値のペアを列挙
+
    For Each entry As KeyValuePair(Of String, Integer) In dict
+
      Console.WriteLine("{0} => {1}", entry.Key, entry.Value)
+
    Next
+

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

          
+
    For Each key As String In dict.Keys
+
      Console.WriteLine(key)
+
    Next
+

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

          
+
    For Each val As Integer In dict.Values
+
      Console.WriteLine(val)
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
foo => 16
+
bar => 72
+
baz => 42
+
[Keys]
+
foo
+
bar
+
baz
+
[Values]
+
16
+
72
+
42
+
}}
+

          
+
Dictionaryクラスには、List.ForEachメソッドのような列挙操作を行うメソッドは用意されていません。
+

          
+
***キーの有無チェックと値の取得
+
Hashtableではキーに該当する要素がない場合はnull(Nothing)が返されるので、とりあえず取得してnullと比較するという方法が取れますが、Dictionaryではキーがない場合は例外がスローされるため事前にキーがあるかどうか調べるなどする必要があります。
+

          
+
&msdn(netfx,id,bb347013){TryGetValueメソッド};を使うと、キーの有無チェックやKeyNotFoundExceptionのキャッチをする必要が無くなります。 キーの有無チェックと値の取得を同時に行えます。 このメソッドは、ContainsKeyメソッドと値の取得を組み合わせた動作をするメソッドと言えます。 キーの有無はTryGetValueメソッドの戻り値で取得でき、キーがある場合は該当する値がoutパラメータに格納されます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections;
+
using System.Collections.Generic;
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    Dictionary<string, int> dict = new Dictionary<string, int>();
+

          
+
    dict["foo"] = 16;
+
    dict["bar"] = 72;
+

          
+
    Hashtable hash = new Hashtable();
+

          
+
    hash["foo"] = 16;
+
    hash["bar"] = 72;
+

          
+
    // Dictionaryからキー"foo"に該当する値を取得
+
    int valDict;
+

          
+
    if (dict.TryGetValue("foo", out valDict))
+
    {
+
      // 取得できたら表示
+
      Console.WriteLine("foo => {0}", valDict);
+
    }
+

          
+
    // Hashtableからキー"foo"に該当する値を取得
+
    object valHash = hash["foo"];
+

          
+
    if (valHash != null)
+
    {
+
      // 取得出来たらintにキャストして表示
+
      Console.WriteLine("foo => {0}", (int)valHash);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections
+
Imports System.Collections.Generic
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim dict As New Dictionary(Of String, Integer)()
+

          
+
    dict("foo") = 16
+
    dict("bar") = 72
+

          
+
    Dim hash As New Hashtable()
+

          
+
    hash("foo") = 16
+
    hash("bar") = 72
+

          
+
    ' Dictionaryからキー"foo"に該当する値を取得
+
    Dim valDict As Integer
+

          
+
    If dict.TryGetValue("foo", valDict) Then
+
      ' 取得できたら表示
+
      Console.WriteLine("foo => {0}", valDict)
+
    End If
+

          
+
    ' Hashtableからキー"foo"に該当する値を取得
+
    Dim valHash As Object = hash("foo")
+

          
+
    If Not valHash Is Nothing Then
+
      ' 取得出来たらIntegerにキャストして表示
+
      Console.WriteLine("foo => {0}", CInt(valHash))
+
    End If
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
foo => 16
+
foo => 16
+
}}
+

          
+
***キー比較のカスタマイズ
+
Hashtableと同様、コンストラクタで適切なIEqualityComparer<T>インターフェイスを指定することで、Dictionaryのキー比較時の動作をカスタマイズ出来ます。 例えば、文字列をキーとした場合に大文字小文字を無視するようにするといったことが出来ます。 以下は、StringComparerクラスを使って、大文字小文字を無視するDictionaryを作成する例です。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    // 大文字小文字の違いを無視しないDictionaryを作成
+
    // (キーの比較にStringComparer.CurrentCultureを使用)
+
    Dictionary<string, int> caseSensitiveDictionary = new Dictionary<string, int>(StringComparer.CurrentCulture);
+

          
+
    caseSensitiveDictionary["foo"] = 1;
+
    caseSensitiveDictionary["bar"] = 2;
+
    caseSensitiveDictionary["FOO"] = 3;
+
    caseSensitiveDictionary["BAR"] = 4;
+

          
+
    // 大文字小文字の違いを無視するDictionaryを作成
+
    // (キーの比較にStringComparer.CurrentCultureIgnoreCaseを使用)
+
    Dictionary<string, int> caseInsensitiveDictionary = new Dictionary<string, int>(StringComparer.CurrentCultureIgnoreCase);
+

          
+
    caseInsensitiveDictionary["foo"] = 1;
+
    caseInsensitiveDictionary["bar"] = 2;
+
    caseInsensitiveDictionary["FOO"] = 3;
+
    caseInsensitiveDictionary["BAR"] = 4;
+

          
+
    Console.WriteLine("caseSensitiveDictionary");
+

          
+
    foreach (KeyValuePair<string, int> entry in caseSensitiveDictionary)
+
    {
+
      Console.WriteLine("{0} => {1}", entry.Key, entry.Value);
+
    }
+

          
+
    Console.WriteLine("caseInsensitiveDictionary");
+

          
+
    foreach (KeyValuePair<string, int> entry in caseInsensitiveDictionary)
+
    {
+
      Console.WriteLine("{0} => {1}", entry.Key, entry.Value);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' 大文字小文字の違いを無視しないDictionaryを作成
+
    ' (キーの比較にStringComparer.CurrentCultureを使用)
+
    Dim caseSensitiveDictionary As New Dictionary(Of String, Integer)(StringComparer.CurrentCulture)
+

          
+
    caseSensitiveDictionary("foo") = 1
+
    caseSensitiveDictionary("bar") = 2
+
    caseSensitiveDictionary("FOO") = 3
+
    caseSensitiveDictionary("BAR") = 4
+

          
+
    ' 大文字小文字の違いを無視するDictionaryを作成
+
    ' (キーの比較にStringComparer.CurrentCultureIgnoreCaseを使用)
+
    Dim caseInsensitiveDictionary As New Dictionary(Of String, Integer)(StringComparer.CurrentCultureIgnoreCase)
+

          
+
    caseInsensitiveDictionary("foo") = 1
+
    caseInsensitiveDictionary("bar") = 2
+
    caseInsensitiveDictionary("FOO") = 3
+
    caseInsensitiveDictionary("BAR") = 4
+

          
+
    Console.WriteLine("caseSensitiveDictionary")
+

          
+
    For Each entry As KeyValuePair(Of String, Integer) In caseSensitiveDictionary
+
      Console.WriteLine("{0} => {1}", entry.Key, entry.Value)
+
    Next
+

          
+
    Console.WriteLine("caseInsensitiveDictionary")
+

          
+
    For Each entry As KeyValuePair(Of String, Integer) In caseInsensitiveDictionary
+
      Console.WriteLine("{0} => {1}", entry.Key, entry.Value)
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
caseSensitiveDictionary
+
foo => 1
+
bar => 2
+
FOO => 3
+
BAR => 4
+
caseInsensitiveDictionary
+
foo => 3
+
bar => 4
+
}}
+

          
+
**&aname(Generic.SortedListSortedDictionary){SortedListとSortedDictionary};
+
&msdn(netfx,id,ms132319){System.Collections.Generic.SortedListクラス};と&msdn(netfx,id,f7fta44c){System.Collections.Generic.SortedDictionaryクラス};は非常によく似たコレクションクラスで、どちらも[[Dictionaryクラス>#Generic.Dictionary]]のようにキーと値のペアで要素を格納し、格納した要素は[[System.Collections.SortedListクラス>#SortedList]]のようにキーに基づいて並べ替えられます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    SortedList<string, int> list = new SortedList<string, int>();
+

          
+
    list.Add("Dave", 1);
+
    list.Add("Alice", 2);
+
    list.Add("Bob", 3);
+
    list.Add("Eve", 4);
+
    list.Add("Charlie", 5);
+

          
+
    Console.WriteLine("[SortedList]");
+

          
+
    foreach (KeyValuePair<string, int> pair in list)
+
    {
+
      Console.WriteLine("{0} => {1}", pair.Key, pair.Value);
+
    }
+

          
+
    SortedDictionary<string, int> dict = new SortedDictionary<string, int>();
+

          
+
    dict.Add("Dave", 1);
+
    dict.Add("Alice", 2);
+
    dict.Add("Bob", 3);
+
    dict.Add("Eve", 4);
+
    dict.Add("Charlie", 5);
+

          
+
    Console.WriteLine("[SortedDictionary]");
+

          
+
    foreach (KeyValuePair<string, int> pair in dict)
+
    {
+
      Console.WriteLine("{0} => {1}", pair.Key, pair.Value);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim list As New SortedList(Of String, Integer)()
+

          
+
    list.Add("Dave", 1)
+
    list.Add("Alice", 2)
+
    list.Add("Bob", 3)
+
    list.Add("Eve", 4)
+
    list.Add("Charlie", 5)
+

          
+
    Console.WriteLine("[SortedList]")
+

          
+
    For Each pair As KeyValuePair(Of String, Integer) In list
+
      Console.WriteLine("{0} => {1}", pair.Key, pair.Value)
+
    Next
+

          
+
    Dim dict As New SortedDictionary(Of String, Integer)()
+

          
+
    dict.Add("Dave", 1)
+
    dict.Add("Alice", 2)
+
    dict.Add("Bob", 3)
+
    dict.Add("Eve", 4)
+
    dict.Add("Charlie", 5)
+

          
+
    Console.WriteLine("[SortedDictionary]")
+

          
+
    For Each pair As KeyValuePair(Of String, Integer) In dict
+
      Console.WriteLine("{0} => {1}", pair.Key, pair.Value)
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
[SortedList]
+
Alice => 2
+
Bob => 3
+
Charlie => 5
+
Dave => 1
+
Eve => 4
+
[SortedDictionary]
+
Alice => 2
+
Bob => 3
+
Charlie => 5
+
Dave => 1
+
Eve => 4
+
}}
+

          
+
***基本操作
+
SortedListクラスとSortedDictionaryクラスでは、ContainsKeyメソッドやTryGetValueメソッドなど、概ね[[Dictionaryクラス>#Generic.Dictionary]]と同様の操作が行えるようになっています。
+

          
+
#tabpage(SortedList/C#)
+
#code(cs){{
+
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");
+
    }
+
  }
+
}
+
}}
+
#tabpage(SortedDictionary/C#)
+
#code(cs){{
+
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");
+
    }
+
  }
+
}
+
}}
+
#tabpage(SortedList/VB)
+
#code(vb){{
+
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
+
}}
+
#tabpage(SortedDictionary/VB)
+
#code(vb){{
+
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
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
True
+
False
+
baz => 42
+
foo => 16
+
value of 'baz': 42
+
key not found
+
}}
+

          
+
SortedListクラスとSortedDictionaryクラスの違いの一つは、SortedListクラスがインデックスを指定したキー・値へのアクセスが出来るのに対し、SortedDictionaryクラスではインデックスを指定したアクセスは出来ない点です。 SortedDictionaryでは出来ず、SortedListでは出来る操作には次のような操作があります。
+

          
+
まず、&msdn(netfx,id,ms132379){Keysプロパティ};および&msdn(netfx,id,ms132380){Valuesプロパティ};を参照することで、インデックスを指定して個々の要素のキーと値を取得できます。 これは、非ジェネリックなSortedListのGetByIndexメソッドに相当します。 ただ、インデックスを指定した値・キーの設定は出来ないため、SetByIndexメソッドに相当する操作はありません。 また、非ジェネリックなSortedListと同じく、&msdn(netfx,id,ms132336){IndexOfKeyメソッド};および&msdn(netfx,id,ms132337){IndexOfValueメソッド};を使うことで、キー・値が格納されている要素のインデックスを取得することが出来ます。 &msdn(netfx,id,ms132339){RemoveAtメソッド};で、インデックスを指定して要素を削除することも出来ます。
+

          
+
以下は、SortedListを使ってインデックスを指定した操作を行う例です。 いずれもSortedDictionaryでは出来ない操作です。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
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} => {2}", i, list.Keys[i], list.Values[i]);
+
    }
+

          
+
    // キー"Charlie"を持つ要素のインデックスを取得
+
    Console.WriteLine("IndexOfKey 'Charlie': {0}", list.IndexOfKey("Charlie"));
+

          
+
    // 値2を持つ要素のインデックスを取得
+
    Console.WriteLine("IndexOfValue 2: {0}", list.IndexOfValue(2));
+

          
+
    // インデックス3の要素を削除
+
    list.RemoveAt(3);
+

          
+
    foreach (KeyValuePair<string, int> pair in list)
+
    {
+
      Console.WriteLine("{0} => {1}", pair.Key, pair.Value);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
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} => {2}", i, list.Keys(i), list.Values(i))
+
    Next
+

          
+
    ' キー"Charlie"を持つ要素のインデックスを取得
+
    Console.WriteLine("IndexOfKey 'Charlie': {0}", list.IndexOfKey("Charlie"))
+

          
+
    ' 値2を持つ要素のインデックスを取得
+
    Console.WriteLine("IndexOfValue 2: {0}", list.IndexOfValue(2))
+

          
+
    ' インデックス3の要素を削除
+
    list.RemoveAt(3)
+

          
+
    For Each pair As KeyValuePair(Of String, Integer) In list
+
      Console.WriteLine("{0} => {1}", pair.Key, pair.Value)
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
[0] Alice => 2
+
[1] Bob => 3
+
[2] Charlie => 5
+
[3] Dave => 1
+
[4] Eve => 4
+
IndexOfKey 'Charlie': 2
+
IndexOfValue 2: 0
+
Alice => 2
+
Bob => 3
+
Charlie => 5
+
Eve => 4
+
}}
+

          
+
***キー比較・ソート順のカスタマイズ
+
[[Dictionary>#Generic.Dictionary]]や[[非ジェネリックなSortedList>#SortedList]]と同じく、コンストラクタで適切なIComparer<T>インターフェイスを指定することで、キー比較時およびソート時の動作をカスタマイズ出来ます。 以下は、大文字小文字を無視し、アルファベット順とは逆順(Z-Aの順)になるようにソートするIComparer<string>を実装し、SortedListおよびSortedDictionaryでの並べ替え順をカスタマイズする例です。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
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()
+
  {
+
    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} => {1}", pair.Key, pair.Value);
+
    }
+

          
+
    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} => {1}", pair.Key, pair.Value);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
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()
+
    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} => {1}", pair.Key, pair.Value)
+
    Next
+

          
+
    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} => {1}", pair.Key, pair.Value)
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
[SortedList]
+
Charlie => 3
+
BOB => 72
+
aLiCe => 16
+
[SortedDictionary]
+
Charlie => 3
+
Bob => 72
+
Alice => 16
+
}}
+

          
+
***パフォーマンスの違い
+
SortedListクラスとSortedDictionaryクラスのもう一つの違いは、使用するメモリの量と挿入・削除の速度です。 SortedListクラスとSortedDictionaryクラスはほとんどの操作は同じですが、インデックスによる操作をサポートするかどうかの実装の違いに起因して、パフォーマンスにも違いが現れます。 &msdn(netfx,id,5z658b67){Sorted コレクション型};によると、両者の違いは次のようになっています。
+

          
+
|*SortedListとSortedDictionaryの相違点&br;(nはコレクション内の要素数)
+
|~相違点|~System.Collections.Generic.SortedList&br;System.Collections.SortedList|~System.Collections.Generic.SortedDictionary|h
+
|~取得の速度|>|どちらもO(log n)|
+
|~挿入・削除の速度|一般にO(n)&br;挿入による並べ替えが発生せず、かつ挿入により内部コレクションのサイズが変わらない場合は、新しい要素が末尾に挿入されるためO(1)|常にO(log n)|
+
|~使用するメモリ量|比較して少ない|比較して多い|
+

          
+
以下は、互いに重複しないシャッフルされたキーを使って要素を追加した場合の速度を比較した結果の一例です。
+

          
+
#code(cs,検証用に使ったコード){{
+
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);
+
    }
+
  }
+
}
+
}}
+

          
+
#prompt(実行結果の一例){{
+
[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を次のように変更し、並べ替えが行われないようキーがソートされた状態にすると結果は反転します。
+

          
+
#code(cs){{
+
static IEnumerable<int> GetShuffledNumbers(int count)
+
{
+
  // ランダムな順番ではなく、ソートが不要な順番で返すようにする
+
  return Enumerable.Range(0, count);
+
}
+
}}
+

          
+
#prompt(実行結果の一例){{
+
[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)となるためです。
+

          
+
**&aname(Generic.LinkedList){LinkedList};
+
&msdn(netfx,id,he2s3bh7){System.Collections.Generic.LinkedListクラス};は双方向の連結リストのデータ構造を提供するコレクションクラスです。 System.Collections名前空間ではLinkedListに相当するクラス、連結リストのデータ構造を持つコレクションクラスは提供されていません。 Listクラスとは異なりインデックスによるアクセスは出来ませんが、追加と削除の操作はListクラスよりも高速(O(1))に行えます。 LinkedListは、格納される要素の前後関係が重視され、かつ追加・削除の操作が多いデータ群を扱う場合などに向いています。
+

          
+
***基本的な操作
+
連結リストを実現するために、LinkedListクラスでは個々の要素は&msdn(netfx,id,ahf4c754){LinkedListNodeクラス};で表されるノードとして格納されます。 LinkedListの先頭のノードは&msdn(netfx,id,ms132187){Firstプロパティ};、末尾のノードは&msdn(netfx,id,ms132188){Lastプロパティ};で取得出来ます。 LinkedListが空の場合、FirstプロパティとLastプロパティはnullを返します。 個々のノードの次のノードは&msdn(netfx,id,b4t9w6be){LinkedListNode.Nextプロパティ};、前のノードは&msdn(netfx,id,de80z2x6){LinkedListNode.Previousプロパティ};で取得できます。 また、ノードの持つ値は&msdn(netfx,id,86397t7k){LinkedListNode.Valueプロパティ};で取得出来ます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    LinkedList<string> list = new LinkedList<string>();
+

          
+
    list.AddFirst("Bob");     // LinkedListの先頭に"Bob"を追加
+
    list.AddLast("Charlie");  // LinkedListの末尾に"Charlie"を追加
+
    list.AddFirst("Alice");   // LinkedListの先頭に"Alice"を追加
+

          
+
    foreach (string e in list)
+
    {
+
      Console.WriteLine(e);
+
    }
+

          
+
    // Console.WriteLine(list[0]); // インデックスによるアクセスは出来ない
+
    Console.WriteLine("First => {0}", list.First.Value); // 最初のノードの値を表示
+
    Console.WriteLine("Last => {0}", list.Last.Value); // 最後のノードの値を表示
+
    Console.WriteLine("First.Next => {0}", list.First.Next.Value); // 最初のノードの、次のノードの値を表示
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim list As New LinkedList(Of String)()
+

          
+
    list.AddFirst("Bob")    ' LinkedListの先頭に"Bob"を追加
+
    list.AddLast("Charlie") ' LinkedListの末尾に"Charlie"を追加
+
    list.AddFirst("Alice")  ' LinkedListの先頭に"Alice"を追加
+

          
+
    For Each e As String In list
+
      Console.WriteLine(e)
+
    Next
+

          
+
    ' Console.WriteLine(list(0)); // インデックスによるアクセスは出来ない
+
    Console.WriteLine("First => {0}", list.First.Value) ' 最初のノードの値を表示
+
    Console.WriteLine("Last => {0}", list.Last.Value) ' 最後のノードの値を表示
+
    Console.WriteLine("First.Next => {0}", list.First.Next.Value) ' 最初のノードの、次のノードの値を表示
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
Alice
+
Bob
+
Charlie
+
First => Alice
+
Last => Charlie
+
First.Next => Bob
+
}}
+

          
+
ノードを追加するには、次のメソッドを使います。 追加の際、既に他のLinkedListに属しているノードを追加しようとした場合、InvalidOperationExceptionがスローされます。 また、追加する値を指定するメソッドでは、戻り値として作成・追加されたノードが返されます。
+

          
+
|*ノードを追加するためのメソッド
+
|~メソッド|~動作|h
+
|>|~追加する値を指定するメソッド|
+
|AddFirst(value)|LinkedListの先頭に値valueのノードを作成して追加する|
+
|AddLast(value)|LinkedListの末尾に値valueのノードを作成して追加する|
+
|AddBefore(node, value)|LinkedList内のノードnodeの前に、値valueのノードを作成して追加する|
+
|AddAfter(node, value)|LinkedList内のノードnodeの後に、値valueのノードを作成して追加する|
+
|>|~追加するノードを指定するメソッド|
+
|AddFirst(node)|LinkedListの先頭にノードnodeを追加する|
+
|AddLast(node)|LinkedListの末尾にノードnodeを追加する|
+
|AddBefore(node, newNode)|LinkedList内のノードnodeの前に、ノードnewNodeを追加する|
+
|AddAfter(node, newNode)|LinkedList内のノードnodeの後に、ノードnewNodeを追加する|
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    LinkedList<string> list = new LinkedList<string>();
+

          
+
    // LinkedListの先頭に"Alice"を追加
+
    LinkedListNode<string> alice = list.AddFirst("Alice");
+

          
+
    // ノード"Alice"の後に"Dave"を追加
+
    LinkedListNode<string> dave = list.AddAfter(alice, "Dave");
+

          
+
    // ノード"Dave"の前に"Charlie"を追加
+
    LinkedListNode<string> charlie = new LinkedListNode<string>("Charlie");
+

          
+
    list.AddBefore(dave, charlie);
+

          
+
    // LinkedListの末尾に"Eve"を追加
+
    list.AddLast("Eve");
+

          
+
    // ノード"Dave"の前の前に"Bob"を追加
+
    list.AddBefore(dave.Previous, "Bob");
+

          
+
    foreach (string e in list)
+
    {
+
      Console.WriteLine(e);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim list As New LinkedList(Of String)()
+

          
+
    ' LinkedListの先頭に"Alice"を追加
+
    Dim alice As LinkedListNode(Of String) = list.AddFirst("Alice")
+

          
+
    ' ノード"Alice"の後に"Dave"を追加
+
    Dim dave As LinkedListNode(Of String) = list.AddAfter(alice, "Dave")
+

          
+
    ' ノード"Dave"の前に"Charlie"を追加
+
    Dim charlie As New LinkedListNode(Of String)("Charlie")
+

          
+
    list.AddBefore(dave, charlie)
+

          
+
    ' LinkedListの末尾に"Eve"を追加
+
    list.AddLast("Eve")
+

          
+
    ' ノード"Dave"の前の前に"Bob"を追加
+
    list.AddBefore(dave.Previous, "Bob")
+

          
+
    For Each e As String In list
+
      Console.WriteLine(e)
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
Alice
+
Bob
+
Charlie
+
Dave
+
Eve
+
}}
+

          
+
ノードを削除するには、次のメソッドを使います。
+

          
+
|*ノードを追加するためのメソッド
+
|~メソッド|~動作|h
+
|RemoveFirst()|先頭にあるノードを削除する|
+
|RemoveLast()|末尾にあるノードを削除する|
+
|Remove(value)|値valueを持つ最初のノード(もっとも前方にあるノード)を削除する|
+
|Remove(node)|指定されたノードnodeを削除する&br;nodeがLinkedListに属していない場合、InvalidOperationExceptionがスローされる|
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    LinkedList<string> list = new LinkedList<string>(new string[] {
+
      "Alice", "Bob", "Charlie", "Dave", "Eve",
+
    });
+

          
+
    LinkedListNode<string> charlie = list.First.Next.Next;
+

          
+
    Print(list);
+

          
+
    // LinkedListからノード"Dave"を削除
+
    Console.WriteLine("[Remove Dave]");
+

          
+
    list.Remove("Dave");
+

          
+
    Print(list);
+

          
+
    // charlieの前のノードを削除
+
    Console.WriteLine("[Remove charlie.Previous]");
+

          
+
    list.Remove(charlie.Previous);
+

          
+
    Print(list);
+

          
+
    // LinkedListの末尾のノードを削除
+
    Console.WriteLine("[RemoveLast]");
+

          
+
    list.RemoveLast();
+

          
+
    Print(list);
+
  }
+

          
+
  static void Print(LinkedList<string> list)
+
  {
+
    foreach (string e in list)
+
    {
+
      Console.WriteLine(e);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim list As New LinkedList(Of String)(New String() { _
+
      "Alice", "Bob", "Charlie", "Dave", "Eve" _
+
    })
+

          
+
    Dim charlie As LinkedListNode(Of String) = list.First.Next.Next
+

          
+
    Print(list)
+

          
+
    ' LinkedListからノード"Dave"を削除
+
    Console.WriteLine("[Remove Dave]")
+

          
+
    list.Remove("Dave")
+

          
+
    Print(list)
+

          
+
    ' charlieの前のノードを削除
+
    Console.WriteLine("[Remove charlie.Previous]")
+

          
+
    list.Remove(charlie.Previous)
+

          
+
    Print(list)
+

          
+
    ' LinkedListの末尾のノードを削除
+
    Console.WriteLine("[RemoveLast]")
+

          
+
    list.RemoveLast()
+

          
+
    Print(list)
+
  End Sub
+

          
+
  Shared Sub Print(ByVal list As LinkedList(Of String))
+
    For Each e As String In list
+
      Console.WriteLine(e)
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
Alice
+
Bob
+
Charlie
+
Dave
+
Eve
+
[Remove Dave]
+
Alice
+
Bob
+
Charlie
+
Eve
+
[Remove charlie.Previous]
+
Alice
+
Charlie
+
Eve
+
[RemoveLast]
+
Alice
+
Charlie
+
}}
+

          
+
***列挙操作
+
既に例にあげたとおり、LinkedListでもforeach文による列挙ができるようになっていますが、インデックスを指定したfor文による列挙は出来ません。 ただし、繰り返し構文とLinkedListNode.Nextプロパティ・LinkedListNode.Previousプロパティを組み合わせることで、任意のノードを起点として列挙を行うことが出来ます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    LinkedList<string> list = new LinkedList<string>(new string[] {
+
      "Alice", "Bob", "Charlie", "Dave", "Eve",
+
    });
+

          
+
    // foreach文による列挙
+
    Console.WriteLine("[foreach]");
+

          
+
    foreach (string e in list)
+
    {
+
      Console.WriteLine(e);
+
    }
+

          
+
    // 末尾のノードから前方にたどって列挙する
+
    Console.WriteLine("[tail to head]");
+

          
+
    for (LinkedListNode<string> node = list.Last; node != null; node = node.Previous)
+
    {
+
      Console.WriteLine(node.Value);
+
    }
+

          
+
    // 先頭の次のノードから後方にたどって列挙する
+
    Console.WriteLine("[head to tail]");
+

          
+
    for (LinkedListNode<string> node = list.First.Next; node != null; node = node.Next)
+
    {
+
      Console.WriteLine(node.Value);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim list As New LinkedList(Of String)(New String() { _
+
      "Alice", "Bob", "Charlie", "Dave", "Eve" _
+
    })
+

          
+
    ' foreach文による列挙
+
    Console.WriteLine("[foreach]")
+

          
+
    For Each e As String In list
+
      Console.WriteLine(e)
+
    Next
+

          
+
    ' 末尾のノードから前方にたどって列挙する
+
    Console.WriteLine("[tail to head]")
+

          
+
    Dim node As LinkedListNode(Of String) = list.Last
+

          
+
    Do While Not node Is Nothing
+
      Console.WriteLine(node.Value)
+

          
+
      node = node.Previous
+
    Loop
+

          
+
    ' 先頭の次のノードから後方にたどって列挙する
+
    Console.WriteLine("[head to tail]")
+

          
+
    node = list.First.Next
+

          
+
    Do While Not node Is Nothing
+
      Console.WriteLine(node.Value)
+

          
+
      node = node.Next
+
    Loop
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
[foreach]
+
Alice
+
Bob
+
Charlie
+
Dave
+
Eve
+
[tail to head]
+
Eve
+
Dave
+
Charlie
+
Bob
+
Alice
+
[head to tail]
+
Bob
+
Charlie
+
Dave
+
Eve
+
}}
+

          
+
***検索
+
LinkedList内の要素の検索を行うためには次のメソッドが使えます。 &msdn(netfx,id,99a4073e){Findメソッド};はLinkedList内にあるノードから指定された値を持つ最初のノードを返します。 &msdn(netfx,id,k03z2s0t){FindLastメソッド};は逆に、指定された値を持つ最後のノードを返します。 いずれのメソッドも、見つからない場合はnull(Nothing)が返されます。 &msdn(netfx,id,dcahk87c){Containsメソッド};は、単純に指定された値を持つノードがあるかどうかを返します。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    LinkedList<int> list = new LinkedList<int>(new int[] {
+
      0, 1, 2, 3, 2, 1, 0,
+
    });
+

          
+
    LinkedListNode<int> found;
+

          
+
    // 値に2を持つ最初のノードを取得する
+
    found = list.Find(2);
+

          
+
    Console.WriteLine("[Find]");
+
    Console.WriteLine("found.Previous: {0}", found.Previous.Value);
+
    Console.WriteLine("found.Next: {0}", found.Next.Value);
+

          
+
    // 値に2を持つ最後のノードを取得する
+
    found = list.FindLast(2);
+

          
+
    Console.WriteLine("[FindLast]");
+
    Console.WriteLine("found.Previous: {0}", found.Previous.Value);
+
    Console.WriteLine("found.Next: {0}", found.Next.Value);
+

          
+
    // 値に1を持つノードがあるかどうか
+
    Console.WriteLine();
+
    Console.WriteLine("Contains(1) = {0}", list.Contains(1));
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim list As New LinkedList(Of Integer)(New Integer() { _
+
      0, 1, 2, 3, 2, 1, 0 _
+
    })
+

          
+
    Dim found As LinkedListNode(Of Integer)
+

          
+
    ' 値に2を持つ最初のノードを取得する
+
    found = list.Find(2)
+