Kolekce (Visual Basic)
U mnoha aplikací chcete vytvářet a spravovat skupiny souvisejících objektů. Existují dva způsoby, jak seskupit objekty: vytvořením polí objektů a vytvořením kolekcí objektů.
Pole jsou nejužitečnější při vytváření a práci s pevným počtem objektů silného typu. Informace o polích naleznete v tématu Pole.
Kolekce poskytují flexibilnější způsob práce se skupinami objektů. Na rozdíl od polí může skupina objektů, se kterými pracujete, dynamicky zvětšovat a zmenšovat podle potřeb aplikace. U některých kolekcí můžete přiřadit klíč k libovolnému objektu, který vložíte do kolekce, abyste mohli objekt rychle načíst pomocí klíče.
Kolekce je třída, takže musíte deklarovat instanci třídy před přidáním prvků do této kolekce.
Pokud kolekce obsahuje prvky pouze jednoho datového typu, můžete použít jednu z tříd v System.Collections.Generic oboru názvů. Obecná kolekce vynucuje bezpečnost typů, aby do ní nelze přidat žádný jiný datový typ. Když načtete prvek z obecné kolekce, nemusíte určit jeho datový typ ani jej převést.
Poznámka:
Příklady v tomto tématu obsahují příkazy Imports pro obory System.Collections.Generic
názvů a System.Linq
obory názvů.
Používání jednoduché kolekce
Příklady v této části používají obecnou List<T> třídu, která umožňuje pracovat se seznamem objektů silného typu.
Následující příklad vytvoří seznam řetězců a pak iteruje řetězce pomocí příkazu For Each... Další příkaz.
' 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
Pokud je obsah kolekce známý předem, můžete k inicializaci kolekce použít inicializátor kolekce. Další informace naleznete v tématu Inicializátory kolekce.
Následující příklad je stejný jako předchozí příklad, s výjimkou inicializátoru kolekce se používá k přidání elementů do kolekce.
' 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
Můžete použít for ... Další příkaz místo For Each
příkazu, který bude iterovat kolekcí. Toho dosáhnete přístupem k prvkům kolekce podle pozice indexu. Index prvků začíná na 0 a končí počtem prvků minus 1.
Následující příklad iteruje prvky kolekce pomocí namísto For…Next
For Each
.
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
Následující příklad odebere prvek z kolekce zadáním objektu, který se má odebrat.
' 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
Následující příklad odebere elementy z obecného seznamu. For Each
Místo příkazu, for... Použije se další příkaz, který iteruje v sestupném pořadí. Důvodem je to, že metoda způsobí, že RemoveAt prvky po odebrání elementu mají nižší hodnotu indexu.
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
Pro typ prvků v sadě List<T>můžete také definovat vlastní třídu. V následujícím příkladu Galaxy
je třída, kterou používá, List<T> definována v kódu.
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
Typy kolekcí
Rozhraní .NET Framework poskytuje řadu běžných kolekcí. Každý typ kolekce je určený pro konkrétní účel.
Některé běžné třídy kolekcí jsou popsány v této části:
System.Collections.Generic – třídy
System.Collections.Concurrent – třídy
System.Collections – třídy
Visual Basic
Collection
– třída
Třídy System.Collections.Generic
Obecnou kolekci můžete vytvořit pomocí jedné z tříd v System.Collections.Generic oboru názvů. Obecná kolekce je užitečná, když má každá položka v kolekci stejný datový typ. Obecná kolekce vynucuje silné psaní tím, že umožňuje přidání pouze požadovaného datového typu.
Následující tabulka uvádí některé často používané třídy System.Collections.Generic oboru názvů:
Třída | Popis |
---|---|
Dictionary<TKey,TValue> | Představuje kolekci párů klíč/hodnota uspořádaných na základě klíče. |
List<T> | Představuje seznam objektů, ke kterým lze přistupovat pomocí indexu. Poskytuje metody pro vyhledávání, řazení a úpravy seznamů. |
Queue<T> | Představuje první kolekci objektů fiFO (first out). |
SortedList<TKey,TValue> | Představuje kolekci párů klíč/hodnota seřazených podle klíče na základě přidružené IComparer<T> implementace. |
Stack<T> | Představuje poslední kolekci objektů (LIFO). |
Další informace naleznete v tématu Běžně používané typy kolekcí, výběr třídy kolekce a System.Collections.Generic.
Třídy System.Collections.Concurrent
V rozhraní .NET Framework 4 nebo novějších poskytují kolekce v System.Collections.Concurrent oboru názvů efektivní operace bezpečné pro přístup k položkám kolekce z více vláken.
Třídy v System.Collections.Concurrent oboru názvů by měly být použity místo odpovídajících typů v oboru System.Collections.Generic názvů a System.Collections vždy, když více vláken přistupuje ke kolekci současně. Další informace naleznete v tématu Thread-Sejf Kolekce a System.Collections.Concurrent.
Některé třídy zahrnuté v System.Collections.Concurrent oboru názvů jsou BlockingCollection<T>, ConcurrentDictionary<TKey,TValue>, ConcurrentQueue<T>a ConcurrentStack<T>.
Třídy System.Collections
Třídy v System.Collections oboru názvů neukládají elementy jako objekty s konkrétním typem, ale jako objekty typu Object
.
Kdykoli je to možné, měli byste místo starších typů v oboru názvů použít obecné kolekce v System.Collections.Generic oboru názvů nebo System.Collections.Concurrent obor System.Collections
názvů.
Následující tabulka uvádí některé často používané třídy v System.Collections
oboru názvů:
Třída | Popis |
---|---|
ArrayList | Představuje pole objektů, jejichž velikost je dynamicky zvýšena podle potřeby. |
Hashtable | Představuje kolekci párů klíč-hodnota uspořádaných podle hodnot hash klíčů. |
Queue | Představuje první kolekci objektů fiFO (first out). |
Stack | Představuje poslední kolekci objektů (LIFO). |
Obor System.Collections.Specialized názvů poskytuje specializované a silně typované třídy kolekcí, jako jsou kolekce pouze řetězce a propojené seznamy a hybridní slovníky.
Třída Collection v jazyce Visual Basic
Třídu Jazyka Visual Basic Collection můžete použít pro přístup k položce kolekce pomocí číselného indexu String
nebo klíče. Položky můžete do objektu kolekce přidat buď pomocí klíče, nebo bez zadání klíče. Pokud přidáte položku bez klíče, musíte pro přístup k ní použít jeho číselný index.
Třída Jazyka Visual Basic Collection
ukládá všechny jeho prvky jako typ Object
, takže můžete přidat položku libovolného datového typu. Neexistuje žádná ochrana proti přidání nevhodných datových typů.
Při použití třídy Visual Basic Collection
má první položka v kolekci index 1. Liší se od tříd kolekce rozhraní .NET Framework, pro které je počáteční index 0.
Kdykoli je to možné, měli byste místo třídy Visual Basic Collection
použít obecné kolekce v System.Collections.Generic oboru názvů nebo System.Collections.Concurrent oboru názvů.
Další informace najdete na webu Collection.
Implementace kolekce párů klíč/hodnota
Obecná Dictionary<TKey,TValue> kolekce umožňuje přístup k prvkům v kolekci pomocí klíče každého prvku. Každý doplněk slovníku se skládá z hodnoty a jeho přidruženého klíče. Načtení hodnoty pomocí klíče je rychlé, protože Dictionary
třída je implementována jako hashovací tabulka.
Následující příklad vytvoří Dictionary
kolekci a iteruje prostřednictvím slovníku For Each
pomocí příkazu.
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
Chcete-li místo toho použít inicializátor kolekce k sestavení Dictionary
kolekce, můžete nahradit BuildDictionary
a AddToDictionary
metody následující metodou.
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
Následující příklad používá metodu ContainsKeyItem[] a vlastnost Dictionary
k rychlému vyhledání položky podle klíče. Tato Item
vlastnost umožňuje přístup k položce v elements
kolekci pomocí elements(symbol)
kódu v jazyce Visual Basic.
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
Následující příklad místo toho používá metodu TryGetValue rychle najít položku podle klíče.
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
Přístup ke kolekci pomocí jazyka LINQ
LINQ (language-integrated Query) se dá použít pro přístup k kolekcím. Dotazy LINQ poskytují možnosti filtrování, řazení a seskupování. Další informace naleznete v tématu Začínáme s LINQ v jazyce Visual Basic.
Následující příklad spustí dotaz LINQ na obecný List
. Dotaz LINQ vrátí jinou kolekci, která obsahuje výsledky.
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
Řazení kolekce
Následující příklad znázorňuje postup řazení kolekce. Příklad seřadí instance Car
třídy, které jsou uloženy v objektu List<T>. Třída Car
implementuje IComparable<T> rozhraní, které vyžaduje, aby CompareTo byla metoda implementována.
Každé volání CompareTo metody vytvoří jedno porovnání, které se používá k řazení. Uživatelem napsaný kód v CompareTo
metodě vrátí hodnotu pro každé porovnání aktuálního objektu s jiným objektem. Vrácená hodnota je menší než nula, pokud je aktuální objekt menší než druhý objekt, větší než nula, pokud je aktuální objekt větší než druhý objekt, a nula, pokud jsou stejné. To umožňuje definovat v kódu kritéria pro větší než, menší než a rovno.
ListCars
Příkaz v cars.Sort()
metodě seřadí seznam. Toto volání Sort metody způsobí, CompareTo
že metoda bude volána automaticky pro Car
objekty v objektu List
List<T> .
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
Definice vlastní kolekce
Kolekci můžete definovat implementací IEnumerable<T> nebo IEnumerable rozhraním. Další informace najdete v tématu Vytvoření výčtu kolekce.
I když můžete definovat vlastní kolekci, je obvykle lepší místo toho použít kolekce, které jsou součástí rozhraní .NET Framework, které jsou popsány v typech kolekcí dříve v tomto tématu.
Následující příklad definuje vlastní třídu kolekce s názvem AllColors
. Tato třída implementuje IEnumerable rozhraní, které vyžaduje, aby GetEnumerator byla metoda implementována.
Metoda GetEnumerator
vrátí instanci ColorEnumerator
třídy. ColorEnumerator
implementuje IEnumerator rozhraní, které vyžaduje implementaci Current vlastnosti, MoveNext metody a Reset metody.
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
Iterátory
Iterátor slouží k provedení vlastní iterace v kolekci. Iterátorem může být metoda nebo get
příslušenství. Iterátor používá příkaz Yield k vrácení každého prvku kolekce po jednom.
Iterátor můžete volat pomocí příkazu For Each... Další příkaz. Každá iterace smyčky For Each
volá iterátor. Yield
Při dosažení příkazu v iterátoru se vrátí výraz a aktuální umístění v kódu se zachová. Spuštění se restartuje z daného umístění při příštím volání iterátoru.
Další informace najdete v tématu Iterátory (Visual Basic).
Následující příklad používá metodu iterátoru. Metoda iterátoru má Yield
příkaz, který je uvnitř objektu For... Další smyčka. ListEvenNumbers
V metodě každá iterace For Each
těla příkazu vytvoří volání metody iterátoru, která pokračuje k dalšímu Yield
příkazu.
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