多くのアプリケーションでは、関連オブジェクトのグループを作成および管理する必要があります。 オブジェクトをグループ化するには、オブジェクトの配列を作成する方法と、オブジェクトのコレクションを作成する方法の 2 つの方法があります。
配列は、厳密に型指定されたオブジェクトの固定数を作成して操作する場合に最も便利です。 配列の詳細については、「 配列」を参照してください。
コレクションは、オブジェクトのグループを操作するためのより柔軟な方法を提供します。 配列とは異なり、使用するオブジェクトのグループは、アプリケーションのニーズの変化に応じて動的に拡大および縮小できます。 一部のコレクションでは、コレクションに配置した任意のオブジェクトにキーを割り当てて、キーを使用してオブジェクトをすばやく取得できるようにすることができます。
コレクションはクラスであるため、そのコレクションに要素を追加する前に、クラスのインスタンスを宣言する必要があります。
コレクションに 1 つのデータ型のみの要素が含まれている場合は、 System.Collections.Generic 名前空間のいずれかのクラスを使用できます。 ジェネリック コレクションでは、他のデータ型を追加できないように、型セーフが適用されます。 ジェネリック コレクションから要素を取得する場合、そのデータ型を決定したり変換したりする必要はありません。
注
このトピックの例では、System.Collections.Generic
および System.Linq
名前空間の Imports ステートメントを含めます。
単純なコレクションの使用
このセクションの例では、ジェネリック List<T> クラスを使用します。これにより、厳密に型指定されたオブジェクトの一覧を操作できます。
次の例では、文字列の一覧を作成し、For Each を使用して文字列を反復処理 します。次の ステートメント。
' Create a list of strings.
Dim salmons As New List(Of String)
salmons.Add("chinook")
salmons.Add("coho")
salmons.Add("pink")
salmons.Add("sockeye")
' Iterate through the list.
For Each salmon As String In salmons
Console.Write(salmon & " ")
Next
'Output: chinook coho pink sockeye
コレクションの内容が事前にわかっている場合は、 コレクション初期化子 を使用してコレクションを初期化できます。 詳細については、「 コレクション初期化子」を参照してください。
次の例は前の例と同じですが、コレクション初期化子を使用してコレクションに要素を追加する点が異なります。
' Create a list of strings by using a
' collection initializer.
Dim salmons As New List(Of String) From
{"chinook", "coho", "pink", "sockeye"}
For Each salmon As String In salmons
Console.Write(salmon & " ")
Next
'Output: chinook coho pink sockeye
For... を使用できます。コレクションを反復処理するFor Each
ステートメントではなく、次のステートメント。 そのためには、インデックス位置によってコレクション要素にアクセスします。 要素のインデックスは 0 から始まり、要素数から 1 を引いた値で終わります。
次の例では、For Each
ではなくFor…Next
を使用してコレクションの要素を反復処理します。
Dim salmons As New List(Of String) From
{"chinook", "coho", "pink", "sockeye"}
For index = 0 To salmons.Count - 1
Console.Write(salmons(index) & " ")
Next
'Output: chinook coho pink sockeye
次の例では、削除するオブジェクトを指定して、コレクションから要素を削除します。
' Create a list of strings by using a
' collection initializer.
Dim salmons As New List(Of String) From
{"chinook", "coho", "pink", "sockeye"}
' Remove an element in the list by specifying
' the object.
salmons.Remove("coho")
For Each salmon As String In salmons
Console.Write(salmon & " ")
Next
'Output: chinook pink sockeye
次の例では、ジェネリック リストから要素を削除します。
For Each
ステートメントの代わりに For...降順で反復処理する次のステートメントが使用されます。 これは、 RemoveAt メソッドによって、削除された要素の後の要素のインデックス値が小さいためです。
Dim numbers As New List(Of Integer) From
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
' Remove odd numbers.
For index As Integer = numbers.Count - 1 To 0 Step -1
If numbers(index) Mod 2 = 1 Then
' Remove the element by specifying
' the zero-based index in the list.
numbers.RemoveAt(index)
End If
Next
' Iterate through the list.
' A lambda expression is placed in the ForEach method
' of the List(T) object.
numbers.ForEach(
Sub(number) Console.Write(number & " "))
' Output: 0 2 4 6 8
List<T>内の要素の型については、独自のクラスを定義することもできます。 次の例では、List<T>によって使用されるGalaxy
クラスがコードで定義されています。
Private Sub IterateThroughList()
Dim theGalaxies As New List(Of Galaxy) From
{
New Galaxy With {.Name = "Tadpole", .MegaLightYears = 400},
New Galaxy With {.Name = "Pinwheel", .MegaLightYears = 25},
New Galaxy With {.Name = "Milky Way", .MegaLightYears = 0},
New Galaxy With {.Name = "Andromeda", .MegaLightYears = 3}
}
For Each theGalaxy In theGalaxies
With theGalaxy
Console.WriteLine(.Name & " " & .MegaLightYears)
End With
Next
' Output:
' Tadpole 400
' Pinwheel 25
' Milky Way 0
' Andromeda 3
End Sub
Public Class Galaxy
Public Property Name As String
Public Property MegaLightYears As Integer
End Class
コレクションの種類
.NET Framework には、多くの一般的なコレクションが用意されています。 コレクションの各種類は、特定の目的のために設計されています。
このセクションでは、一般的なコレクション クラスの一部について説明します。
Visual Basic
Collection
クラス
System.Collections.Generic クラス
System.Collections.Generic名前空間のいずれかのクラスを使用して、ジェネリック コレクションを作成できます。 ジェネリック コレクションは、コレクション内のすべての項目が同じデータ型を持つ場合に便利です。 ジェネリック コレクションでは、必要なデータ型のみを追加できるようにすることで、厳密な型指定を適用します。
次の表に、 System.Collections.Generic 名前空間のよく使用されるクラスの一部を示します。
クラス | 説明 |
---|---|
Dictionary<TKey,TValue> | キーに基づいて編成されたキーと値のペアのコレクションを表します。 |
List<T> | インデックスでアクセスできるオブジェクトの一覧を表します。 リストの検索、並べ替え、変更を行うメソッドを提供します。 |
Queue<T> | オブジェクトの先入れ先出し (FIFO) コレクションを表します。 |
SortedList<TKey,TValue> | 関連付けられている IComparer<T> 実装に基づいてキーで並べ替えられるキーと値のペアのコレクションを表します。 |
Stack<T> | オブジェクトの最後の in、first out (LIFO) コレクションを表します。 |
詳細については、「 一般的に使用されるコレクション型、 コレクション クラスの選択、および System.Collections.Generic」を参照してください。
System.Collections.Concurrent クラス
.NET Framework 4 以降では、 System.Collections.Concurrent 名前空間のコレクションは、複数のスレッドからコレクション項目にアクセスするための効率的なスレッド セーフな操作を提供します。
System.Collections.Concurrent名前空間のクラスは、複数のスレッドがコレクションに同時にアクセスする場合は常に、System.Collections.GenericおよびSystem.Collections名前空間の対応する型の代わりに使用する必要があります。 詳細については、「Thread-Safe コレクションとSystem.Collections.Concurrent」を参照してください。
System.Collections.Concurrent名前空間に含まれる一部のクラスは、BlockingCollection<T>、ConcurrentDictionary<TKey,TValue>、ConcurrentQueue<T>、およびConcurrentStack<T>です。
System.Collections クラス
System.Collections名前空間のクラスは、要素を具体的に型指定されたオブジェクトとして格納するのではなく、Object
型のオブジェクトとして格納します。
可能な限り、System.Collections
名前空間のレガシ型ではなく、System.Collections.Generic名前空間またはSystem.Collections.Concurrent名前空間のジェネリック コレクションを使用する必要があります。
次の表に、 System.Collections
名前空間で頻繁に使用されるクラスの一部を示します。
クラス | 説明 |
---|---|
ArrayList | 必要に応じてサイズが動的に増加するオブジェクトの配列を表します。 |
Hashtable | キーのハッシュ コードに基づいて編成された、キーと値のペアのコレクションを表します。 |
Queue | オブジェクトの先入れ先出し (FIFO) コレクションを表します。 |
Stack | オブジェクトの最後の in、first out (LIFO) コレクションを表します。 |
System.Collections.Specialized名前空間は、文字列のみのコレクションやリンク リスト、ハイブリッド ディクショナリなど、特殊で厳密に型指定されたコレクション クラスを提供します。
Visual Basic コレクション クラス
Visual Basic Collection クラスを使用すると、数値インデックスまたは String
キーを使用してコレクション項目にアクセスできます。 コレクション オブジェクトに項目を追加するには、キーを指定する場合と指定しない場合があります。 キーのない項目を追加する場合は、その数値インデックスを使用してアクセスする必要があります。
Visual Basic Collection
クラスは、すべての要素を型 Object
として格納するため、任意のデータ型の項目を追加できます。 不適切なデータ型の追加に対する保護はありません。
Visual Basic Collection
クラスを使用する場合、コレクション内の最初の項目のインデックスは 1 になります。 これは、開始インデックスが 0 である .NET Framework コレクション クラスとは異なります。
可能な限り、Visual Basic Collection
クラスの代わりに、System.Collections.Generic名前空間またはSystem.Collections.Concurrent名前空間のジェネリック コレクションを使用する必要があります。
詳細については、Collectionを参照してください。
キーと値のペアのコレクションの実装
Dictionary<TKey,TValue>ジェネリック コレクションを使用すると、各要素のキーを使用してコレクション内の要素にアクセスできます。 ディクショナリへの各追加は、値とそれに関連付けられているキーで構成されます。
Dictionary
クラスはハッシュ テーブルとして実装されているため、キーを使用した値の取得は高速です。
次の例では、 Dictionary
コレクションを作成し、 For Each
ステートメントを使用してディクショナリを反復処理します。
Private Sub IterateThroughDictionary()
Dim elements As Dictionary(Of String, Element) = BuildDictionary()
For Each kvp As KeyValuePair(Of String, Element) In elements
Dim theElement As Element = kvp.Value
Console.WriteLine("key: " & kvp.Key)
With theElement
Console.WriteLine("values: " & .Symbol & " " &
.Name & " " & .AtomicNumber)
End With
Next
End Sub
Private Function BuildDictionary() As Dictionary(Of String, Element)
Dim elements As New Dictionary(Of String, Element)
AddToDictionary(elements, "K", "Potassium", 19)
AddToDictionary(elements, "Ca", "Calcium", 20)
AddToDictionary(elements, "Sc", "Scandium", 21)
AddToDictionary(elements, "Ti", "Titanium", 22)
Return elements
End Function
Private Sub AddToDictionary(ByVal elements As Dictionary(Of String, Element),
ByVal symbol As String, ByVal name As String, ByVal atomicNumber As Integer)
Dim theElement As New Element
theElement.Symbol = symbol
theElement.Name = name
theElement.AtomicNumber = atomicNumber
elements.Add(Key:=theElement.Symbol, value:=theElement)
End Sub
Public Class Element
Public Property Symbol As String
Public Property Name As String
Public Property AtomicNumber As Integer
End Class
代わりにコレクション初期化子を使用して Dictionary
コレクションをビルドするには、 BuildDictionary
メソッドと AddToDictionary
メソッドを次のメソッドに置き換えます。
Private Function BuildDictionary2() As Dictionary(Of String, Element)
Return New Dictionary(Of String, Element) From
{
{"K", New Element With
{.Symbol = "K", .Name = "Potassium", .AtomicNumber = 19}},
{"Ca", New Element With
{.Symbol = "Ca", .Name = "Calcium", .AtomicNumber = 20}},
{"Sc", New Element With
{.Symbol = "Sc", .Name = "Scandium", .AtomicNumber = 21}},
{"Ti", New Element With
{.Symbol = "Ti", .Name = "Titanium", .AtomicNumber = 22}}
}
End Function
次の例では、ContainsKey メソッドと Dictionary
の Item[] プロパティを使用して、キーで項目をすばやく検索します。
Item
プロパティを使用すると、Visual Basic のelements(symbol)
コードを使用して、elements
コレクション内の項目にアクセスできます。
Private Sub FindInDictionary(ByVal symbol As String)
Dim elements As Dictionary(Of String, Element) = BuildDictionary()
If elements.ContainsKey(symbol) = False Then
Console.WriteLine(symbol & " not found")
Else
Dim theElement = elements(symbol)
Console.WriteLine("found: " & theElement.Name)
End If
End Sub
代わりに、 TryGetValue メソッドを使用して、キーで項目をすばやく検索する例を次に示します。
Private Sub FindInDictionary2(ByVal symbol As String)
Dim elements As Dictionary(Of String, Element) = BuildDictionary()
Dim theElement As Element = Nothing
If elements.TryGetValue(symbol, theElement) = False Then
Console.WriteLine(symbol & " not found")
Else
Console.WriteLine("found: " & theElement.Name)
End If
End Sub
LINQ を使用してコレクションにアクセスする
LINQ (Language-Integrated クエリ) を使用してコレクションにアクセスできます。 LINQ クエリは、フィルター処理、順序付け、およびグループ化の機能を提供します。 詳細については、「 Visual Basic での LINQ の概要」を参照してください。
次の例では、汎用 List
に対して LINQ クエリを実行します。 LINQ クエリは、結果を含む別のコレクションを返します。
Private Sub ShowLINQ()
Dim elements As List(Of Element) = BuildList()
' LINQ Query.
Dim subset = From theElement In elements
Where theElement.AtomicNumber < 22
Order By theElement.Name
For Each theElement In subset
Console.WriteLine(theElement.Name & " " & theElement.AtomicNumber)
Next
' Output:
' Calcium 20
' Potassium 19
' Scandium 21
End Sub
Private Function BuildList() As List(Of Element)
Return New List(Of Element) From
{
{New Element With
{.Symbol = "K", .Name = "Potassium", .AtomicNumber = 19}},
{New Element With
{.Symbol = "Ca", .Name = "Calcium", .AtomicNumber = 20}},
{New Element With
{.Symbol = "Sc", .Name = "Scandium", .AtomicNumber = 21}},
{New Element With
{.Symbol = "Ti", .Name = "Titanium", .AtomicNumber = 22}}
}
End Function
Public Class Element
Public Property Symbol As String
Public Property Name As String
Public Property AtomicNumber As Integer
End Class
コレクションの並べ替え
次の例は、コレクションを並べ替える手順を示しています。 この例では、List<T>に格納されているCar
クラスのインスタンスを並べ替えます。
Car
クラスは、IComparable<T> インターフェイスを実装します。そのためには、CompareTo メソッドを実装する必要があります。
CompareTo メソッドを呼び出すたびに、並べ替えに使用される 1 つの比較が行われます。
CompareTo
メソッドのユーザー記述コードは、現在のオブジェクトと別のオブジェクトの比較ごとに値を返します。 現在のオブジェクトが他のオブジェクトより小さい場合、返される値は 0 未満、現在のオブジェクトが他のオブジェクトより大きい場合は 0 より大きく、等しい場合は 0 になります。 これにより、より大きい、より小さい、等しいという条件をコードで定義できます。
ListCars
メソッドでは、cars.Sort()
ステートメントによってリストが並べ替えられます。 このList<T>のSort メソッドを呼び出すと、List
内のCar
オブジェクトに対してCompareTo
メソッドが自動的に呼び出されます。
Public Sub ListCars()
' Create some new cars.
Dim cars As New List(Of Car) From
{
New Car With {.Name = "car1", .Color = "blue", .Speed = 20},
New Car With {.Name = "car2", .Color = "red", .Speed = 50},
New Car With {.Name = "car3", .Color = "green", .Speed = 10},
New Car With {.Name = "car4", .Color = "blue", .Speed = 50},
New Car With {.Name = "car5", .Color = "blue", .Speed = 30},
New Car With {.Name = "car6", .Color = "red", .Speed = 60},
New Car With {.Name = "car7", .Color = "green", .Speed = 50}
}
' Sort the cars by color alphabetically, and then by speed
' in descending order.
cars.Sort()
' View all of the cars.
For Each thisCar As Car In cars
Console.Write(thisCar.Color.PadRight(5) & " ")
Console.Write(thisCar.Speed.ToString & " ")
Console.Write(thisCar.Name)
Console.WriteLine()
Next
' Output:
' blue 50 car4
' blue 30 car5
' blue 20 car1
' green 50 car7
' green 10 car3
' red 60 car6
' red 50 car2
End Sub
Public Class Car
Implements IComparable(Of Car)
Public Property Name As String
Public Property Speed As Integer
Public Property Color As String
Public Function CompareTo(ByVal other As Car) As Integer _
Implements System.IComparable(Of Car).CompareTo
' A call to this method makes a single comparison that is
' used for sorting.
' Determine the relative order of the objects being compared.
' Sort by color alphabetically, and then by speed in
' descending order.
' Compare the colors.
Dim compare As Integer
compare = String.Compare(Me.Color, other.Color, True)
' If the colors are the same, compare the speeds.
If compare = 0 Then
compare = Me.Speed.CompareTo(other.Speed)
' Use descending order for speed.
compare = -compare
End If
Return compare
End Function
End Class
カスタム コレクションの定義
IEnumerable<T>またはIEnumerable インターフェイスを実装することで、コレクションを定義できます。 詳細については、「 コレクションの列挙」を参照してください。
カスタム コレクションは定義できますが、通常は.NET Framework に含まれているコレクションを使用することをお勧めします。これについては、このトピックの「 コレクションの種類 」で説明されています。
次の例では、 AllColors
という名前のカスタム コレクション クラスを定義します。 このクラスは、 IEnumerable インターフェイスを実装します。そのためには、 GetEnumerator メソッドを実装する必要があります。
GetEnumerator
メソッドは、ColorEnumerator
クラスのインスタンスを返します。
ColorEnumerator
は、Current プロパティ、MoveNext メソッド、およびReset メソッドを実装する必要があるIEnumerator インターフェイスを実装します。
Public Sub ListColors()
Dim colors As New AllColors()
For Each theColor As Color In colors
Console.Write(theColor.Name & " ")
Next
Console.WriteLine()
' Output: red blue green
End Sub
' Collection class.
Public Class AllColors
Implements System.Collections.IEnumerable
Private _colors() As Color =
{
New Color With {.Name = "red"},
New Color With {.Name = "blue"},
New Color With {.Name = "green"}
}
Public Function GetEnumerator() As System.Collections.IEnumerator _
Implements System.Collections.IEnumerable.GetEnumerator
Return New ColorEnumerator(_colors)
' Instead of creating a custom enumerator, you could
' use the GetEnumerator of the array.
'Return _colors.GetEnumerator
End Function
' Custom enumerator.
Private Class ColorEnumerator
Implements System.Collections.IEnumerator
Private _colors() As Color
Private _position As Integer = -1
Public Sub New(ByVal colors() As Color)
_colors = colors
End Sub
Public ReadOnly Property Current() As Object _
Implements System.Collections.IEnumerator.Current
Get
Return _colors(_position)
End Get
End Property
Public Function MoveNext() As Boolean _
Implements System.Collections.IEnumerator.MoveNext
_position += 1
Return (_position < _colors.Length)
End Function
Public Sub Reset() Implements System.Collections.IEnumerator.Reset
_position = -1
End Sub
End Class
End Class
' Element class.
Public Class Color
Public Property Name As String
End Class
反復子
反復子は、コレクションに対してカスタムイテレーションを実行するために使用されます。 反復子には、メソッドまたは get
アクセサーを指定できます。 反復子は Yield ステートメントを使用して、コレクションの各要素を一度に 1 つずつ返します。
For Each... を使用して反復子を呼び出します 。次の ステートメント。
For Each
ループの各反復処理で反復子が呼び出されます。 反復子で Yield
ステートメントに到達すると、式が返され、コード内の現在の位置が保持されます。 次に反復子が呼び出されるときに、その場所から実行が再開されます。
詳細については、「 反復子 (Visual Basic)」を参照してください。
次の例では、反復子メソッドを使用します。 反復子メソッドには、For... 内にYield
ステートメントがあります。次のループ。
ListEvenNumbers
メソッドでは、For Each
ステートメント本体の各反復処理によって反復子メソッドの呼び出しが作成され、次の Yield
ステートメントに進みます。
Public Sub ListEvenNumbers()
For Each number As Integer In EvenSequence(5, 18)
Console.Write(number & " ")
Next
Console.WriteLine()
' Output: 6 8 10 12 14 16 18
End Sub
Private Iterator Function EvenSequence(
ByVal firstNumber As Integer, ByVal lastNumber As Integer) _
As IEnumerable(Of Integer)
' Yield even numbers in the range.
For number = firstNumber To lastNumber
If number Mod 2 = 0 Then
Yield number
End If
Next
End Function
こちらも参照ください
.NET