次の方法で共有


コレクション (Visual Basic)

多くのアプリケーションでは、関連オブジェクトのグループを作成および管理する必要があります。 オブジェクトをグループ化するには、オブジェクトの配列を作成する方法と、オブジェクトのコレクションを作成する方法の 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 には、多くの一般的なコレクションが用意されています。 コレクションの各種類は、特定の目的のために設計されています。

このセクションでは、一般的なコレクション クラスの一部について説明します。

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 メソッドと DictionaryItem[] プロパティを使用して、キーで項目をすばやく検索します。 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

こちらも参照ください