Wszystko, co chciałeś wiedzieć o tablicach

Tablice są podstawową funkcją języka większości języków programowania. Są one kolekcją wartości lub obiektów, które są trudne do uniknięcia. 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. Zapoznaj się ze swoim blogiem 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 przeniosę się na inne sposoby, w jaki program PowerShell korzysta z nich.

Tablica to struktura danych, która służy jako kolekcja wielu elementów. Można iterować tablicę 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.

Dotknę każdego z tych szczegółów, gdy pójdziemy.

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

Pusta tablica może zostać utworzona przy użyciu polecenia @()

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

Możemy utworzyć tablicę i umieścić ją z wartościami, 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, otrzymujemy 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 rozdzielone przecinkami działają przez większość czasu.

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

Zapisywanie danych wyjściowych w celu utworzenia tablic

Jedną z fajnych małych sztuczek, o których warto wspomnieć, jest to, że można użyć Write-Output do szybkiego tworzenia ciągów w konsoli programu .

$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 skrycie, 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żyjemy 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, jest to, że pierwszy element znajduje się na początku listy, więc 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 z przesunięciem 3.

PS> $data[3]
Three

Indeks

Teraz możesz zobaczyć, dlaczego wybrałem wartości, które zrobiłem w tym przykładzie. Wprowadził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 wrócić do pojedynczego elementu. 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 kolejności podanych indeksów. Jeśli zduplikujesz indeks, otrzymasz ten element za oba razy.

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. Jeśli więc 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 myśleć, że wylicza wszystkie elementy, jeśli zapomnisz o tym szczegółach. $data[0..-1] Daje taką samą wartość jak $data[0,-1] w przypadku podania pierwszego i ostatniego elementu w tablicy (i żadnej z pozostałych 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 próbujesz uzyskać dostęp do indeksu elementu, który znajduje się obok końca tablicy, wystąpi błąd lub wyjątek. Program PowerShell w trybie dyskretnym nie zwraca niczego.

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

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

Jeśli zmienna to $null i próbujesz ją zaindeksować w taki sposób, jak tablica 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.

Upewnij się, że tablice nie $null są przed podjęciem próby uzyskania dostępu do elementów wewnątrz nich.

Count

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 dać liczbę 1.

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

Ma nawet $null 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 przeglądać, gdy zakrywam sprawdzanie $null lub puste tablice w dalszej części tego artykułu.

Błędy poza jednym

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

Pierwszy z nich polega na mentalnym myśleniu, że chcesz drugiego elementu i używasz indeksu 2 i naprawdę otrzymujesz trzeci element. 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 całkowicie szczęśliwy, aby to zrobić i dać ci dokładnie, jaki element istnieje w indeksie 4: $null. Należy użyć polecenia $data.count - 1 lub -1 tego, którego dowiedzieliśmy się o powyższych tematach.

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ę na mnie, ż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ęstszym sposobem jest iterowanie listy i nie zatrzymywanie w odpowiednim czasie. Omówię to, kiedy mówimy o używaniu 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 przeszłości ostatnim elementem, 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

Ponawiam tę akcję później, kiedy mówię o tym, jak zwiększyć tablicę.

Iteracja

W pewnym momencie może być konieczne przejście lub iterowanie całej listy i wykonanie pewnej 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 wiesz, że jest to to samo co $_. Można użyć jednej z nich, ponieważ obie 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łanie .ForEach() kolekcji.

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

Parametr .foreach() przyjmuje 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 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, że musimy 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 pętli, zwróć szczególną for uwagę na warunek. Kiedyś $index -lt $data.count tutaj. Ł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 nieco błędne. 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 ciekawych 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 przejść do tablicy i zaktualizować wewnątrz niej wartości, 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ż mówiliśmy, dotyczą 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, podobnie 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

Lub za pomocą 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 jej złożoności.

Filtrowanie obiektu where-object

W tym miejscu 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 elementu dla 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 zamienić całego obiektu w ten sposób. Jeśli spróbujesz przypisać nowy obiekt do $person zmiennej, aktualizujesz odwołanie do zmiennej do innej, która 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.

-Dołączyć

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 lubię operator -join , jest to, że obsługuje pojedyncze elementy.

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 uwagę. Jeśli kiedykolwiek chcesz dołączyć do wszystkiego bez ogranicznika, zamiast wykonywać następujące czynności:

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

Można użyć -join z tablicą jako parametru bez prefiksu. Spójrz na ten przykład, aby zobaczyć, że mówię o.

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

-Zawiera

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

-Cala

Jeśli masz pojedynczą 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

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

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

Za chwilę omówię to, kiedy mówimy o testowaniu dla programu $null.

-Mecz

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

W przypadku użycia -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 poście o nazwie Wiele sposobów używania wyrażenia regularnego.

$null lub puste

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

Na pierwszy rzut oka ta instrukcja wygląda na to, że powinna działać.

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

Ale po prostu przeszedł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 będzie ona oceniana $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. To sprawia, że 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 tutaj. Można użyć count obiektu nawet w przypadku pojedynczego obiektu, chyba że ten obiekt jest PSCustomObject. Jest to usterka usunięta w programie PowerShell 6.1. To dobra wiadomość, ale wiele osób jest jeszcze 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 opakowować 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ź $null, a następnie sprawdź liczbę.

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

Wszystkie -eq

Niedawno 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

Na tym etapie 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 rozwinąć 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ę. Biorąc wię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 += funkcji duplikowania i tworzenia nowej tablicy. Nie jest to problem w przypadku 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 używaniu potoku, myślimy o typowych wierszach programu PowerShell. Możemy wykorzystać potok z instrukcjami foreach() i innymi pętlami. Dlatego zamiast dodawać elementy do tablicy w pętli, możemy upuszczać 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 z PSObject typu.

Silnie typizowane tablice

Tablicę dowolnego typu można utworzyć przy użyciu podobnej składni. Podczas tworzenia silnie typizowanej tablicy może 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'

ArrayList

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, z którą można szybciej pracować. Działa jak tablica obiektów w każdym miejscu, którego potrzebujemy, ale obsługuje szybkie dodawanie elementów.

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

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

Wywołujemy platformę .NET, aby uzyskać ten typ. W tym przypadku używamy domyślnego konstruktora 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ą utworzyć 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. Element StringBuilder jest specjalnie zaprojektowany pod kątem wydajności.

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

Lista ogólna

Typ ogólny to specjalny typ w języku C#, który definiuje uogólnioną klasę, 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ę intstring lub typy.

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 listę podobną do tej bez uprzedniego utworzenia obiektu:

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

Składnię można skrócić za pomocą instrukcji using namespace w programie PowerShell 5 i nowszych. 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 metody ArrayList nie ma wartości Add zwracanej, więc nie musimy jej używać void .

$myList.Add(10)

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()

Elementy 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 true wartość , jeśli była w stanie znaleźć i usunąć element z kolekcji.

Więcej kolekcji

Istnieje wiele innych kolekcji, które mogą być używane, ale są to dobre ogólne zamiany tablicy. Jeśli chcesz dowiedzieć się więcej o tych opcjach, zapoznaj się z tym Gist , który Mark Kraus ułożył.

Inne niuanse

Teraz, gdy omówiłem wszystkie główne funkcje, oto kilka innych rzeczy, które 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

Typowym scenariuszem jest utworzenie tablicy ze wszystkimi zerami. Jeśli masz tylko liczby całkowite, silnie typizowana tablica liczb całkowitych jest domyślnie ustawiona na wszystkie zera.

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

Dobrą 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 tablic tablic, gdy dane mieszczą się w siatce, takiej jak wzorzec.

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śniejszy 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ę. Korzystając z powyższych $data , w ten sposób 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 drogę stamtąd.

Write-Output -NoEnumerate

Program PowerShell lubi odpakowywać lub wyliczać tablice. Jest to podstawowy aspekt sposobu korzystania z potoku przez program PowerShell, ale czasami nie chcesz, aby tak się stało.

Często potokuje obiekty, aby Get-Member dowiedzieć się więcej o nich. Gdy potokuję do niej tablicę, zostanie ona rozpasana i polecenie Get-Member zobaczy 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ę unikać hacks jak to). Przecinek można umieścić przed tablicą przed jego potokiem. Spowoduje to zawinięcie $data do innej tablicy, w której jest jedynym elementem, więc po rozpakuj zewnętrzną tablicę wrócimy $data do rozpaku.

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

Zwracanie tablicy

To rozpakuj tablice również wtedy, gdy zwracasz wartości wyjściowe lub zwracane z funkcji. Nadal można 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 wystąpi 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 osobami, które uważasz, że może uzyskać z niego wartość.

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