Wszystko, co chcesz wiedzieć o tablicach

Tablice są podstawową funkcją języka większości języków programowania. Są to kolekcje wartości lub obiektów, których trudno uniknąć. Przyjrzyjmy się bliżej tablicom i wszystkim, co mają do zaoferowania.

Uwaga

Oryginalna wersja tego artykułu pojawiła się na blogu napisanym przez @KevinMarquette. Zespół programu PowerShell dziękuje Kevinowi za udostępnienie tej zawartości nam. Sprawdź swój blog na PowerShellExplained.com.

Co to jest tablica?

Zaczynam od podstawowego opisu technicznego, czym są tablice i jak są one używane przez większość języków programowania, zanim przejdę do innych sposobów korzystania z nich przez program PowerShell.

Tablica to struktura danych, która służy jako kolekcja wielu elementów. Można iterować po tablicy lub uzyskiwać dostęp do poszczególnych elementów przy użyciu indeksu. Tablica jest tworzona jako sekwencyjny fragment pamięci, w którym każda wartość jest przechowywana bezpośrednio obok drugiej.

Będę dotykać każdego z tych szczegółów, jak idziemy.

Podstawowy sposób użycia

Ponieważ tablice są tak podstawową funkcją programu PowerShell, istnieje prosta składnia do pracy z nimi w programie PowerShell.

Tworzenie tablicy

Pustą tablicę można utworzyć przy użyciu polecenia @()

PS> $data = @()
PS> $data.count
0

Możemy utworzyć tablicę i umieścić ją w wartościach, umieszczając je w @() nawiasach.

PS> $data = @('Zero','One','Two','Three')
PS> $data.count
4

PS> $data
Zero
One
Two
Three

Ta tablica zawiera 4 elementy. Po wywołaniu zmiennej $data zobaczymy listę naszych elementów. Jeśli jest to tablica ciągów, uzyskamy jeden wiersz na ciąg.

Możemy zadeklarować tablicę w wielu wierszach. Przecinek jest opcjonalny w tym przypadku i ogólnie pominięty.

$data = @(
    'Zero'
    'One'
    'Two'
    'Three'
)

Wolę zadeklarować moje tablice w wielu wierszach w ten sposób. Nie tylko ułatwia odczytywanie wielu elementów, ale także ułatwia porównywanie z poprzednimi wersjami podczas korzystania z kontroli źródła.

Inna składnia

Powszechnie rozumie się, że @() jest to składnia tworzenia tablicy, ale listy rozdzielane przecinkami działają przez większość czasu.

$data = 'Zero','One','Two','Three'

Write-Output do tworzenia tablic

Jedną z ciekawych drobnych sztuczk, o których warto wspomnieć, jest to, że można użyć Write-Output do szybkiego tworzenia ciągów w konsoli.

$data = Write-Output Zero One Two Three

Jest to przydatne, ponieważ nie trzeba umieszczać cudzysłowów wokół ciągów, gdy parametr akceptuje ciągi. Nigdy bym tego nie zrobił w skryscie, ale to uczciwa gra w konsoli.

Uzyskiwanie dostępu do elementów

Teraz, gdy masz tablicę z elementami, możesz chcieć uzyskać dostęp do tych elementów i zaktualizować je.

Przesunięcie

Aby uzyskać dostęp do poszczególnych elementów, używamy nawiasów [] z wartością przesunięcia zaczynającą się od 0. W ten sposób uzyskamy pierwszy element w naszej tablicy:

PS> $data = 'Zero','One','Two','Three'
PS> $data[0]
Zero

Powodem, dla którego używamy zera w tym miejscu, jest to, że pierwszy element znajduje się na początku listy, dlatego używamy przesunięcia 0 elementów, aby uzyskać do niego dostęp. Aby przejść do drugiego elementu, musimy użyć przesunięcia 1, aby pominąć pierwszy element.

PS> $data[1]
One

Oznaczałoby to, że ostatni element jest przesunięty 3.

PS> $data[3]
Three

Indeks

Teraz możesz zobaczyć, dlaczego wybrałem wartości, które zrobiłem na potrzeby tego przykładu. Przedstawiłem to jako przesunięcie, ponieważ jest to, co naprawdę jest, ale to przesunięcie jest częściej określane jako indeks. Indeks rozpoczynający się od 0. W pozostałej części tego artykułu wywołam przesunięcie indeksu.

Specjalne wskazówki dotyczące indeksu

W większości języków można określić tylko jedną liczbę jako indeks i uzyskać pojedynczy element z powrotem. Program PowerShell jest znacznie bardziej elastyczny. Jednocześnie można użyć wielu indeksów. Podając listę indeksów, możemy wybrać kilka elementów.

PS> $data[0,2,3]
Zero
Two
Three

Elementy są zwracane na podstawie podanej kolejności indeksów. W przypadku zduplikowania indeksu otrzymasz ten element w obu przypadkach.

PS> $data[3,0,3]
Three
Zero
Three

Możemy określić sekwencję liczb za pomocą wbudowanego .. operatora.

PS> $data[1..3]
One
Two
Three

Działa to również odwrotnie.

PS> $data[3..1]
Three
Two
One

Wartości indeksu ujemnego można użyć do przesunięcia od końca. Dlatego jeśli potrzebujesz ostatniego elementu na liście, możesz użyć polecenia -1.

PS> $data[-1]
Three

Jedno słowo ostrożności tutaj z operatorem .. . Sekwencja 0..-1 i -1..0 ocena wartości 0,-1 i -1,0. Łatwo jest zobaczyć $data[0..-1] i pomyśleć, że wylicza wszystkie elementy, jeśli zapomnisz o tym szczegółach. $data[0..-1] Daje tę samą wartość, co $data[0,-1] daje pierwszy i ostatni element w tablicy (i żadna z innych wartości). Oto większy przykład:

PS> $a = 1,2,3,4,5,6,7,8
PS> $a[2..-1]
3
2
1
8

Jest to takie samo, jak:

PS> $a[2,1,0,-1]
3
2
1
8

Poza granicami

W większości języków, jeśli spróbujesz uzyskać dostęp do indeksu elementu, który znajduje się poza końcem tablicy, wystąpi jakiś typ błędu lub wyjątku. Program PowerShell w trybie dyskretnym nie zwraca niczego.

PS> $null -eq $data[9000]
True

Nie można indeksowania do tablicy o wartości null

Jeśli zmienna to $null i próbujesz zaindeksować ją jak tablicę System.Management.Automation.RuntimeException , otrzymasz wyjątek z komunikatem Cannot index into a null array.

PS> $empty = $null
PS> $empty[0]
Error: Cannot index into a null array.

Przed próbą uzyskania dostępu do elementów wewnątrz nich upewnij się, że tablice nie $null są dostępne.

Liczba

Tablice i inne kolekcje mają właściwość count, która informuje o liczbie elementów w tablicy.

PS> $data.count
4

Program PowerShell 3.0 dodał właściwość count do większości obiektów. możesz mieć pojedynczy obiekt i powinien podać liczbę 1.

PS> $date = Get-Date
PS> $date.count
1

Nawet $null ma właściwość count, z tą różnicą, że zwraca wartość 0.

PS> $null.count
0

Istnieją tu pułapki, które będę ponownie odwiedzać, gdy zakrywam sprawdzanie $null lub puste tablice w dalszej części tego artykułu.

Błędy poza jednym

Typowy błąd programowania jest tworzony, ponieważ tablice zaczynają się od indeksu 0. Błędy poza jednym można wprowadzić na dwa sposoby.

Pierwszy polega na mentalnym myśleniu, że chcesz drugiego elementu i przy użyciu indeksu 2 i naprawdę uzyskanie trzeciego elementu. Lub myśląc, że masz cztery elementy i chcesz ostatni element, więc użyjesz liczby, aby uzyskać dostęp do ostatniego elementu.

$data[ $data.count ]

Program PowerShell jest doskonale szczęśliwy, aby to zrobić i dać Ci dokładnie to, co istnieje w indeksie 4: $null. Należy użyć polecenia $data.count - 1 lub tych -1 , których dowiedzieliśmy się powyżej.

PS> $data[ $data.count - 1 ]
Three

W tym miejscu możesz użyć indeksu -1 , aby uzyskać ostatni element.

PS> $data[ -1 ]
Three

Lee Dailey zwrócił również uwagę mi, że możemy użyć $data.GetUpperBound(0) , aby uzyskać maksymalną liczbę indeksów.

PS> $data.GetUpperBound(0)
3
PS> $data[ $data.GetUpperBound(0) ]
Three

Drugim najczęściej spotykanym sposobem jest iterowanie listy i nie zatrzymywanie w odpowiednim czasie. Omówię to ponownie, kiedy mówimy o korzystaniu z for pętli .

Aktualizowanie elementów

Możemy użyć tego samego indeksu, aby zaktualizować istniejące elementy w tablicy. Daje nam to bezpośredni dostęp do aktualizowania poszczególnych elementów.

$data[2] = 'dos'
$data[3] = 'tres'

Jeśli spróbujemy zaktualizować element, który jest obok ostatniego elementu, wystąpi Index was outside the bounds of the array. błąd.

PS> $data[4] = 'four'
Index was outside the bounds of the array.
At line:1 char:1
+ $data[4] = 'four'
+ ~~~~~~~~~~~~~
+ CategoryInfo          : OperationStopped: (:) [], IndexOutOfRangeException
+ FullyQualifiedErrorId : System.IndexOutOfRangeException

Omówię to później, kiedy mówię o tym, jak zwiększyć tablicę.

Iteracja

W pewnym momencie może być konieczne chodzenie lub iterowanie całej listy i wykonywanie akcji dla każdego elementu w tablicy.

Potok

Tablice i potok programu PowerShell są przeznaczone dla siebie nawzajem. Jest to jeden z najprostszych sposobów przetwarzania tych wartości. Po przekazaniu tablicy do potoku każdy element wewnątrz tablicy jest przetwarzany indywidualnie.

PS> $data = 'Zero','One','Two','Three'
PS> $data | ForEach-Object {"Item: [$PSItem]"}
Item: [Zero]
Item: [One]
Item: [Two]
Item: [Three]

Jeśli nie widziałeś $PSItem wcześniej, po prostu wiem, że jest to to samo co $_. Można użyć jednego z nich, ponieważ oba te obiekty reprezentują bieżący obiekt w potoku.

Pętla ForEach

Pętla ForEach działa dobrze z kolekcjami. Przy użyciu składni: foreach ( <variable> in <collection> )

foreach ( $node in $data )
{
    "Item: [$node]"
}

ForEach, metoda

Mam tendencję do zapominania o tym, ale działa dobrze w przypadku prostych operacji. Program PowerShell umożliwia wywoływanie .ForEach() kolekcji.

PS> $data.foreach({"Item [$PSItem]"})
Item [Zero]
Item [One]
Item [Two]
Item [Three]

Przyjmuje .foreach() parametr, który jest blokiem skryptu. Nawiasy można usunąć i po prostu podać blok skryptu.

$data.foreach{"Item [$PSItem]"}

Jest to mniej znana składnia, ale działa tylko tak samo. Ta foreach metoda została dodana w programie PowerShell 4.0.

Pętla for

Pętla for jest używana mocno w większości innych języków, ale nie widzisz jej zbyt wiele w programie PowerShell. Gdy to zobaczysz, często jest to w kontekście chodzenia tablicy.

for ( $index = 0; $index -lt $data.count; $index++)
{
    "Item: [{0}]" -f $data[$index]
}

Pierwszą rzeczą, którą robimy, jest zainicjowanie elementu $index do 0. Następnie dodamy warunek, który $index musi być mniejszy niż $data.count. Na koniec określamy, że za każdym razem, gdy zapętlamy pętlę , należy zwiększyć indeks o wartość 1. W tym przypadku $index++ jest to skrót od $index = $index + 1. Operator formatu (-f) służy do wstawiania wartości $data[$index] w ciągu wyjściowym.

Za każdym razem, gdy używasz for pętli, zwróć szczególną uwagę na warunek. Kiedyś tutaj.$index -lt $data.count Łatwo jest uzyskać warunek nieco źle, aby uzyskać błąd off-by-one w logice. Używanie $index -le $data.count lub $index -lt ($data.count - 1) kiedykolwiek jest tak lekko złe. Spowodowałoby to przetworzenie zbyt wielu lub zbyt kilku elementów. Jest to klasyczny błąd off-by-one.

Pętla przełącznika

Jest to taki, który jest łatwy do przeoczenia. Jeśli podasz tablicę do instrukcji switch, sprawdza każdy element w tablicy.

$data = 'Zero','One','Two','Three'
switch( $data )
{
    'One'
    {
        'Tock'
    }
    'Three'
    {
        'Tock'
    }
    Default
    {
        'Tick'
    }
}
Tick
Tock
Tick
Tock

Istnieje wiele fajnych rzeczy, które możemy zrobić za pomocą instrukcji switch. Mam inny artykuł poświęcony temu.

Aktualizowanie wartości

Gdy tablica jest kolekcją ciągów lub liczb całkowitych (typów wartości), czasami warto zaktualizować wartości w tablicy podczas ich pętli. Większość powyższych pętli używa zmiennej w pętli, która przechowuje kopię wartości. W przypadku zaktualizowania tej zmiennej oryginalna wartość w tablicy nie zostanie zaktualizowana.

Wyjątkiem od tej instrukcji jest pętla for . Jeśli chcesz chodzić o tablicę i aktualizować wartości wewnątrz, pętla for jest tym, czego szukasz.

for ( $index = 0; $index -lt $data.count; $index++ )
{
    $data[$index] = "Item: [{0}]" -f $data[$index]
}

Ten przykład przyjmuje wartość według indeksu, wprowadza kilka zmian, a następnie używa tego samego indeksu, aby przypisać go z powrotem.

Tablice obiektów

Do tej pory jedyną rzeczą, którą umieściliśmy w tablicy, jest typ wartości, ale tablice mogą również zawierać obiekty.

$data = @(
    [pscustomobject]@{FirstName='Kevin';LastName='Marquette'}
    [pscustomobject]@{FirstName='John'; LastName='Doe'}
)

Wiele poleceń cmdlet zwraca kolekcje obiektów jako tablice podczas przypisywania ich do zmiennej.

$processList = Get-Process

Wszystkie podstawowe funkcje, o których już rozmawialiśmy, mają zastosowanie do tablic obiektów z kilkoma szczegółami, które warto zwrócić uwagę.

Uzyskiwanie dostępu do właściwości

Możemy użyć indeksu, aby uzyskać dostęp do pojedynczego elementu w kolekcji tak jak w przypadku typów wartości.

PS> $data[0]

FirstName LastName
-----     ----
Kevin     Marquette

Możemy uzyskać bezpośredni dostęp do właściwości i aktualizować je.

PS> $data[0].FirstName

Kevin

PS> $data[0].FirstName = 'Jay'
PS> $data[0]

FirstName LastName
-----     ----
Jay       Marquette

Właściwości tablicy

Zwykle należy wyliczyć całą listę, taką jak ta, aby uzyskać dostęp do wszystkich właściwości:

PS> $data | ForEach-Object {$_.LastName}

Marquette
Doe

Możesz też użyć Select-Object -ExpandProperty polecenia cmdlet .

PS> $data | Select-Object -ExpandProperty LastName

Marquette
Doe

Jednak program PowerShell oferuje nam możliwość bezpośredniego żądania LastName . Program PowerShell wylicza je wszystkie dla nas i zwraca czystą listę.

PS> $data.LastName

Marquette
Doe

Wyliczenie nadal występuje, ale nie widzimy za nią złożoności.

filtrowanie Where-Object

Jest to miejsce, w którym Where-Object możemy filtrować i wybierać, co chcemy z tablicy na podstawie właściwości obiektu.

PS> $data | Where-Object {$_.FirstName -eq 'Kevin'}

FirstName LastName
-----     ----
Kevin     Marquette

Możemy napisać to samo zapytanie, aby uzyskać FirstName szukane dane.

$data | Where FirstName -eq Kevin

Where()

Tablice mają na nich metodę Where() , która umożliwia określenie scriptblock filtru.

$data.Where({$_.FirstName -eq 'Kevin'})

Ta funkcja została dodana w programie PowerShell 4.0.

Aktualizowanie obiektów w pętlach

W przypadku typów wartości jedynym sposobem aktualizacji tablicy jest użycie pętli for, ponieważ musimy znać indeks, aby zastąpić wartość. Mamy więcej opcji z obiektami, ponieważ są to typy odwołań. Oto szybki przykład:

foreach($person in $data)
{
    $person.FirstName = 'Kevin'
}

Ta pętla przechodzi każdy obiekt w tablicy $data . Ponieważ obiekty są typami referencyjnymi, zmienna $person odwołuje się do dokładnie tego samego obiektu, który znajduje się w tablicy. Dlatego aktualizacje jego właściwości aktualizują oryginał.

Nadal nie można zastąpić całego obiektu w ten sposób. Jeśli spróbujesz przypisać nowy obiekt do zmiennej $person , aktualizujesz odwołanie do zmiennej do innego obiektu, które nie wskazuje już oryginalnego obiektu w tablicy. Nie działa to tak, jakby można było oczekiwać:

foreach($person in $data)
{
    $person = [pscustomobject]@{
        FirstName='Kevin'
        LastName='Marquette'
    }
}

Operatory

Operatory w programie PowerShell działają również na tablicach. Niektóre z nich działają nieco inaczej.

-join

Operator -join jest najbardziej oczywisty, więc najpierw przyjrzyjmy się temu operatorowi. Lubię -join operatora i często go używam. Łączy wszystkie elementy w tablicy z określonym znakiem lub ciągiem.

PS> $data = @(1,2,3,4)
PS> $data -join '-'
1-2-3-4
PS> $data -join ','
1,2,3,4

Jedną z funkcji, które podoba mi się operator -join , jest obsługa pojedynczych elementów.

PS> 1 -join '-'
1

Używam tego wewnątrz rejestrowania i pełnych komunikatów.

PS> $data = @(1,2,3,4)
PS> "Data is $($data -join ',')."
Data is 1,2,3,4.

-join $array

Oto sprytna sztuczka, którą Lee Dailey zwrócił do mnie. Jeśli kiedykolwiek chcesz dołączyć wszystko bez ogranicznika, zamiast robić to:

PS> $data = @(1,2,3,4)
PS> $data -join $null
1234

Tablicę można użyć -join jako parametru bez prefiksu. Przyjrzyj się temu przykładowi, aby zobaczyć, że mówię o tym.

PS> $data = @(1,2,3,4)
PS> -join $data
1234

-replace i -split

Inne operatory, takie jak -replace i -split wykonywane na każdym elemencie w tablicy. Nie mogę powiedzieć, że kiedykolwiek używałem ich w ten sposób, ale oto przykład.

PS> $data = @('ATX-SQL-01','ATX-SQL-02','ATX-SQL-03')
PS> $data -replace 'ATX','LAX'
LAX-SQL-01
LAX-SQL-02
LAX-SQL-03

-contains

Operator -contains umożliwia sprawdzenie tablicy wartości, aby sprawdzić, czy zawiera określoną wartość.

PS> $data = @('red','green','blue')
PS> $data -contains 'green'
True

-in

Jeśli masz jedną wartość, którą chcesz zweryfikować, pasuje do jednej z kilku wartości, możesz użyć -in operatora . Wartość będzie znajdować się po lewej stronie, a tablica po prawej stronie operatora.

PS> $data = @('red','green','blue')
PS> 'green' -in $data
True

Może to być kosztowne, jeśli lista jest duża. Często używam wzorca wyrażenia regularnego, jeśli sprawdzam więcej niż kilka wartości.

PS> $data = @('red','green','blue')
PS> $pattern = "^({0})$" -f ($data -join '|')
PS> $pattern
^(red|green|blue)$

PS> 'green' -match $pattern
True

-eq i -ne

Równość i tablice mogą być skomplikowane. Gdy tablica znajduje się po lewej stronie, każdy element jest porównywany. Zamiast zwracać Trueelement , zwraca obiekt, który jest zgodny.

PS> $data = @('red','green','blue')
PS> $data -eq 'green'
green

Gdy używasz -ne operatora, otrzymujemy wszystkie wartości, które nie są równe naszej wartości.

PS> $data = @('red','green','blue')
PS> $data -ne 'green'
red
blue

Gdy używasz tego w instrukcji if() , zwracana wartość jest wartością True . Jeśli żadna wartość nie jest zwracana, jest False to wartość. Oba te następne instrukcje są obliczane na Truewartość .

$data = @('red','green','blue')
if ( $data -eq 'green' )
{
    'Green was found'
}
if ( $data -ne 'green' )
{
    'And green was not found'
}

Zajmę się tym w chwilę, kiedy mówimy o testowaniu dla $nullprogramu .

-match

Operator -match próbuje dopasować każdy element w kolekcji.

PS> $servers = @(
    'LAX-SQL-01'
    'LAX-API-01'
    'ATX-SQL-01'
    'ATX-API-01'
)
PS> $servers -match 'SQL'
LAX-SQL-01
ATX-SQL-01

Gdy używasz -match z pojedynczą wartością, specjalna zmienna $Matches zostanie wypełniona informacjami o dopasowaniach. Nie jest tak, gdy tablica jest przetwarzana w ten sposób.

Możemy podjąć to samo podejście za pomocą polecenia Select-String.

$servers | Select-String SQL

Przyjrzyję się bliżej Select-String,-match a zmienna $matches w innym wpisie o nazwie Wiele sposobów używania wyrażenia regularnego.

$null lub puste

$null Testowanie dla lub pustych tablic może być trudne. Oto typowe pułapki z tablicami.

Na pierwszy rzut oka ta instrukcja wygląda następująco: powinna działać.

if ( $array -eq $null)
{
    'Array is $null'
}

Ale po prostu przejechałem, jak -eq sprawdza każdy element w tablicy. W związku z tym możemy mieć tablicę kilku elementów z pojedynczą wartością $null i można ją ocenić $true

$array = @('one',$null,'three')
if ( $array -eq $null)
{
    'I think Array is $null, but I would be wrong'
}

Dlatego najlepszym rozwiązaniem jest umieszczenie $null elementu po lewej stronie operatora. Dzięki temu ten scenariusz nie jest problemem.

if ( $null -eq $array )
{
    'Array actually is $null'
}

Tablica $null nie jest taka sama jak pusta tablica. Jeśli wiesz, że masz tablicę, sprawdź liczbę obiektów w niej. Jeśli tablica to $null, liczba to 0.

if ( $array.count -gt 0 )
{
    "Array isn't empty"
}

Jest jeszcze jedna pułapka, aby uważać na to. Możesz użyć count obiektu nawet wtedy, gdy masz jeden obiekt, chyba że ten obiekt jest obiektem PSCustomObject. Jest to usterka usunięta w programie PowerShell 6.1. To dobra wiadomość, ale wiele osób jest nadal na 5,1 i musi uważać na to.

PS> $object = [PSCustomObject]@{Name='TestObject'}
PS> $object.count
$null

Jeśli nadal używasz programu PowerShell 5.1, możesz owinąć obiekt w tablicy przed sprawdzeniem liczby, aby uzyskać dokładną liczbę.

if ( @($array).count -gt 0 )
{
    "Array isn't empty"
}

Aby w pełni grać bezpiecznie, sprawdź $nullwartość , a następnie sprawdź liczbę.

if ( $null -ne $array -and @($array).count -gt 0 )
{
    "Array isn't empty"
}

Wszystkie -eq

Niedawno zobaczyłem, jak ktoś zapytać, jak sprawdzić, czy każda wartość w tablicy jest zgodna z daną wartością. Użytkownik Reddit /u/bis miał to sprytne rozwiązanie , które sprawdza wszelkie nieprawidłowe wartości, a następnie przerzuca wynik.

$results = Test-Something
if ( -not ( $results -ne 'Passed') )
{
    'All results a Passed'
}

Dodawanie do tablic

W tym momencie zaczynasz zastanawiać się, jak dodać elementy do tablicy. Szybka odpowiedź polega na tym, że nie można. Tablica jest stałym rozmiarem w pamięci. Jeśli musisz go zwiększyć lub dodać do niego pojedynczy element, musisz utworzyć nową tablicę i skopiować wszystkie wartości ze starej tablicy. Brzmi to jak wiele pracy, jednak program PowerShell ukrywa złożoność tworzenia nowej tablicy. Program PowerShell implementuje operator dodawania (+) dla tablic.

Uwaga

Program PowerShell nie implementuje operacji odejmowania. Jeśli potrzebujesz elastycznej alternatywy dla tablicy, musisz użyć obiektu ogólnego List .

Dodawanie tablicy

Możemy użyć operatora dodawania z tablicami, aby utworzyć nową tablicę. W związku z tym, biorąc pod uwagę te dwie tablice:

$first = @(
    'Zero'
    'One'
)
$second = @(
    'Two'
    'Three'
)

Możemy dodać je razem, aby uzyskać nową tablicę.

PS> $first + $second

Zero
One
Two
Three

Plus równa +=

Możemy utworzyć nową tablicę i dodać do niej element w następujący sposób:

$data = @(
    'Zero'
    'One'
    'Two'
    'Three'
)
$data += 'four'

Pamiętaj, że za każdym razem, gdy używasz += duplikowania i tworzenia nowej tablicy. Nie jest to problem dla małych zestawów danych, ale jest bardzo słabo skalowany.

Przypisanie potoku

Wyniki dowolnego potoku można przypisać do zmiennej. Jest to tablica, jeśli zawiera wiele elementów.

$array = 1..5 | ForEach-Object {
    "ATX-SQL-$PSItem"
}

Zwykle, gdy myślimy o korzystaniu z potoku, myślimy o typowych elementach jednowierszowych programu PowerShell. Możemy wykorzystać potok z instrukcjami foreach() i innymi pętlami. Dlatego zamiast dodawać elementy do tablicy w pętli, możemy upuścić elementy do potoku.

$array = foreach ( $node in (1..5))
{
    "ATX-SQL-$node"
}

Typy tablic

Domyślnie tablica w programie PowerShell jest tworzona [PSObject[]] jako typ. Dzięki temu może zawierać dowolny typ obiektu lub wartości. Działa to, ponieważ wszystko jest dziedziczone po typie PSObject .

Silnie typizowane tablice

Tablicę dowolnego typu można utworzyć przy użyciu podobnej składni. Podczas tworzenia silnie typizowanej tablicy może ona zawierać tylko wartości lub obiekty określonego typu.

PS> [int[]] $numbers = 1,2,3
PS> [int[]] $numbers2 = 'one','two','three'
ERROR: Cannot convert value "one" to type "System.Int32". Input string was not in a correct format."

PS> [string[]] $strings = 'one','two','three'

Tablicalista

Dodawanie elementów do tablicy jest jednym z największych ograniczeń, ale istnieje kilka innych kolekcji, które możemy zwrócić się do tego problemu.

Jest ArrayList to często jedna z pierwszych rzeczy, o których myślimy, gdy potrzebujemy tablicy, która jest szybsza do pracy. Działa jak tablica obiektów w każdym miejscu, którego potrzebujemy, ale szybko obsługuje dodawanie elementów.

Poniżej przedstawiono sposób tworzenia elementów ArrayList i dodawania do niego elementów.

$myarray = [System.Collections.ArrayList]::new()
[void]$myArray.Add('Value')

Wywołujemy program .NET, aby uzyskać ten typ. W tym przypadku używamy konstruktora domyślnego do jego utworzenia. Następnie wywołujemy metodę Add , aby dodać do niej element.

Powodem, dla którego używam [void] na początku wiersza, jest pominięcie kodu powrotnego. Niektóre wywołania platformy .NET to robią i mogą tworzyć nieoczekiwane dane wyjściowe.

Jeśli jedynymi danymi, które masz w tablicy, są ciągi, zapoznaj się również z użyciem narzędzia StringBuilder. Jest to prawie takie samo, ale ma kilka metod, które są przeznaczone tylko do radzenia sobie z ciągami. Jest StringBuilder specjalnie zaprojektowany pod kątem wydajności.

Często można zobaczyć, jak ludzie przechodzą z ArrayList tablic. Ale pochodzi od czasu, w którym język C# nie ma ogólnego wsparcia. Element ArrayList jest przestarzały w obsłudze ogólnej List[]

Lista ogólna

Typ ogólny to specjalny typ w języku C#, który definiuje uogólnionej klasy, a użytkownik określa typy danych, których używa podczas tworzenia. Jeśli więc chcesz wyświetlić listę liczb lub ciągów, zdefiniujesz listę typów lubstring.int

Poniżej przedstawiono sposób tworzenia listy dla ciągów.

$mylist = [System.Collections.Generic.List[string]]::new()

Lub lista liczb.

$mylist = [System.Collections.Generic.List[int]]::new()

Możemy rzutować istniejącą tablicę na taką listę bez uprzedniego utworzenia obiektu:

$mylist = [System.Collections.Generic.List[int]]@(1,2,3)

Składnię można skrócić za using namespace pomocą instrukcji w programie PowerShell 5 i nowszym. Instrukcja using musi być pierwszym wierszem skryptu. Deklarując przestrzeń nazw, program PowerShell umożliwia pozostawienie go poza typami danych podczas odwołowania się do nich.

using namespace System.Collections.Generic
$myList = [List[int]]@(1,2,3)

To sprawia, że List znacznie bardziej użyteczne.

Masz dostępną podobną Add metodę. W przeciwieństwie do tablicyList nie ma wartości zwracanej dla Add metody, więc nie musimy jej używać void .

$myList.Add(10)

I nadal możemy uzyskać dostęp do elementów, takich jak inne tablice.

PS> $myList[-1]
10

List[PSObject]

Możesz mieć listę dowolnego typu, ale jeśli nie znasz typu obiektów, możesz użyć [List[PSObject]] ich do ich przechowywania.

$list = [List[PSObject]]::new()

Remove()

Klasy ArrayList i ogólne List[] obsługują usuwanie elementów z kolekcji.

using namespace System.Collections.Generic
$myList = [List[string]]@('Zero','One','Two','Three')
[void]$myList.Remove("Two")
Zero
One
Three

Podczas pracy z typami wartości usuwa pierwszy z listy. Możesz wywołać ją ponownie, aby zachować usunięcie tej wartości. Jeśli masz typy odwołań, musisz podać obiekt, który chcesz usunąć.

[list[System.Management.Automation.PSDriveInfo]]$drives = Get-PSDrive
$drives.remove($drives[2])
$delete = $drives[2]
$drives.remove($delete)

Metoda remove zwraca wartość true , jeśli była w stanie znaleźć i usunąć element z kolekcji.

Więcej kolekcji

Istnieje wiele innych kolekcji, których można użyć, ale są to dobre ogólne zamiany tablic. Jeśli chcesz dowiedzieć się więcej o tych opcjach, zapoznaj się z tym Gist , który Mark Kraus połączył.

Inne niuanse

Teraz, gdy omówiłem wszystkie główne funkcje, oto kilka innych rzeczy, o których chciałem wspomnieć, zanim podsumuję to.

Tablice o rozmiarze wstępnym

Wspomniałem, że nie można zmienić rozmiaru tablicy po jej utworzeniu. Możemy utworzyć tablicę wstępnie określonego rozmiaru, wywołując ją za pomocą konstruktora new($size) .

$data = [Object[]]::new(4)
$data.count
4

Mnożenie tablic

Interesującą małą sztuczką jest to, że można pomnożyć tablicę przez liczbę całkowitą.

PS> $data = @('red','green','blue')
PS> $data * 3
red
green
blue
red
green
blue
red
green
blue

Inicjowanie za pomocą 0

Typowy scenariusz polega na tym, że chcesz utworzyć tablicę ze wszystkimi zerami. Jeśli masz tylko liczby całkowite, silnie typizowana tablica liczb całkowitych domyślnie jest równa zerom.

PS> [int[]]::new(4)
0
0
0
0

Możemy również użyć sztuczki mnożenia, aby to zrobić.

PS> $data = @(0) * 4
PS> $data
0
0
0
0

Fajną rzeczą w pomnożeniu sztuczki jest to, że można użyć dowolnej wartości. Więc jeśli wolisz mieć 255 wartość domyślną, byłoby to dobrym sposobem, aby to zrobić.

PS> $data = @(255) * 4
PS> $data
255
255
255
255

Zagnieżdżone tablice

Tablica wewnątrz tablicy nosi nazwę tablicy zagnieżdżonej. Nie używam tych elementów w programie PowerShell, ale używałem ich więcej w innych językach. Rozważ użycie tablicy, gdy dane pasują do wzorca przypominającego siatkę.

Poniżej przedstawiono dwa sposoby tworzenia tablicy dwuwymiarowej.

$data = @(@(1,2,3),@(4,5,6),@(7,8,9))

$data2 = @(
    @(1,2,3),
    @(4,5,6),
    @(7,8,9)
)

Przecinek jest bardzo ważny w tych przykładach. Dałem wcześniej przykład normalnej tablicy w wielu wierszach, w których przecinek był opcjonalny. Tak nie jest w przypadku tablicy wielowymiarowej.

Sposób użycia notacji indeksu zmienia się nieco teraz, gdy mamy zagnieżdżona tablicę. Przy użyciu powyższej $data metody uzyskujemy dostęp do wartości 3.

PS> $outside = 0
PS> $inside = 2
PS> $data[$outside][$inside]
3

Dodaj zestaw nawiasów dla każdego poziomu zagnieżdżania tablicy. Pierwszy zestaw nawiasów jest przeznaczony dla najbardziej zewnętrznej tablicy, a następnie pracujesz w drodze stamtąd.

Write-Output -NoEnumerate

Program PowerShell lubi odpakowywać lub wyliczać tablice. Jest to podstawowy aspekt sposobu, w jaki program PowerShell używa potoku, ale czasami nie chcesz tego robić.

Często potokuje obiekty, aby Get-Member dowiedzieć się więcej o nich. Gdy potokuję do niej tablicę, staje się niezapisany i Get-Member widzi elementy członkowskie tablicy, a nie rzeczywistą tablicę.

PS> $data = @('red','green','blue')
PS> $data | Get-Member
TypeName: System.String
...

Aby zapobiec odpakowaniu tablicy, możesz użyć polecenia Write-Output -NoEnumerate.

PS> Write-Output -NoEnumerate $data | Get-Member
TypeName: System.Object[]
...

Mam drugi sposób, że jest bardziej hack (i staram się uniknąć hacki jak to). Przed tablicą można umieścić przecinek przed jego potokiem.

PS> ,$data | Get-Member
TypeName: System.Object[]
...

Zwracanie tablicy

To rozpakuj tablice również wtedy, gdy zwracasz wartości z funkcji lub zwracasz je. Nadal możesz uzyskać tablicę, jeśli przypiszesz dane wyjściowe do zmiennej, więc nie jest to często problem.

Przechwycenie polega na tym, że masz nową tablicę. Jeśli kiedykolwiek jest to problem, możesz go użyć Write-Output -NoEnumerate $array lub return ,$array obejść.

Czy coś jeszcze?

Wiem, że to wszystko jest dużo do podjęcia. Mam nadzieję, że nauczysz się czegoś z tego artykułu za każdym razem, gdy go czytasz i że okazuje się być dobrym odniesieniem dla Ciebie przez długi czas. Jeśli okaże się, że jest to przydatne, podziel się nim z innymi, które uważasz, że może uzyskać wartość z niego.

Z tego miejsca polecam wyewidencjonować podobny post, który pisałem o tabelach skrótów.