A programnyelvek egyik legalapvetőbb adattípusa a tömb , ami ugye egy olyan változó, amely értékek egy halmazát tartalmazza. Nézzük meg az egyszerű tömböktől kezdve a többdimenziós tömbökig a lehetőségeket!
A PowerShell nagyon rugalmasan, akár a parancssorban gyorsan begépelhető módon kezeli a tömböket:
[17] PS C:\> $egésztömb = 1,2,11,22,100
[18] PS C:\> $egésztömb
1
2
11
22
100
[19] PS C:\> $egésztömb.gettype()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
Látszik, hogy a tömbök létrehozásához és adatainak megadásához legegyszerűbben a vessző (, ) karakter használatos.
A PowerShellben a tömbök nem csak egyforma típusú elemeket tartalmazhatnak:
[21] PS C:\> $vegyestömb = "szöveg", 123, 666d, 3.1415
[22] PS C:\> $vegyestömb
szöveg
123
666
3,1415
Hogyan lehet egyelemű tömböt létrehozni?
[23] PS C:\> $nemegyelemű = "elem"
[24] PS C:\> $nemegyelemű
elem
[25] PS C:\> $nemegyelemű.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.Object
A fenti példában a [23]-as promptnál látszik, hogy egyszerűen egy tagot megadva természetesen – ahogy korábban is láttuk – nem jön létre egyelemű tömb. De egy kis trükkel ez is megoldható:
[26] PS C:\> $egyelemű = ,"elem"
[27] PS C:\> $egyelemű
elem
[28] PS C:\> $egyelemű.gettype()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
Ilyenkor tehát a [26]-os promptban alkalmazott trükköt érdemes használni, azaz az elem elé egy vesszőt kell rakni.
Mi van akkor, ha üres tömböt akarunk létrehozni, mert majd később, egy ciklussal akarjuk feltölteni elemekkel? Ehhez ezt a formátumot lehet használni:
[29] PS C:\> $ürestömb = @()
[30] PS C:\> $ürestömb.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
Ezt a „@()” jelölést természetesen egy- és többelemű tömbök létrehozására is felhasználhatjuk:
[31] PS C:\> $eet = @(1)
[32] PS C:\> $eet
1
[33] PS C:\> $eet.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
[34] PS C:\> $tet = @(1,2,3,4)
[35] PS C:\> $tet
1
2
3
4
[36] PS C:\> $tet.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
Vajon hogyan tudok egy olyan tömböt létrehozni, ami további tömböket tartalmaz? Ez sem bonyolult:
PS C:\> $tömböktömbje = @(@(1,2),@(3,4))
PS C:\> $tömböktömbje.Count
2
A $tömböktömbje tehát egy kételemű tömb, aminek mindkét eleme szintén 1-1 kételemű tömb.
PS C:\> $tömböktömbje[0]
1
2
PS C:\> $tömböktömbje[0][1]
2
PS C:\> $tömböktömbje[1]
3
4
Megjegyzés
Sajnos itt sem egyszerű egyelemű tömbök tömbjét létrehozni:
PS C:\> $egyeleműtt = @(@(1,2))
PS C:\> $egyeleműtt.Count
2
Látható, hogy a várt 1 elem helyett a Count 2-t adott, szóval itt is élni kell a vesszős trükkel:
PS C:\> $egyeleműtt = @(,@(1,2))
PS C:\> $egyeleműtt.Count
1
PS C:\> $egyeleműtt[0]
1
2
Ha már ennyit foglalkoztunk tömbökkel, nézzük meg, hogy milyen tulajdonságaik és metódusaik vannak:
[37] PS C:\> $tet | Get-Member
TypeName: System.Int32
Name MemberType Definition
---- ---------- ----------
CompareTo Method System.Int32 CompareTo(Object value), System.Int3...
Equals Method System.Boolean Equals(Object obj), System.Boolean...
GetHashCode Method System.Int32 GetHashCode()
GetType Method System.Type GetType()
GetTypeCode Method System.TypeCode GetTypeCode()
ToString Method System.String ToString(), System.String ToString(...
Hoppá! Ez valahogy nem jó! A négy számot tartalmazó tömbünk esetében a Get-Member nem magának a tömbnek, hanem a tömb egyes elemeinek adta meg a tagjellemzőit. Hogyan lehetne rábírni, hogy magának a tömbnek a tagjellemzőit adja vissza? Segíteni kell az előbb látott, egyelemű tömbre vonatkozó (,) trükkel:
[38] PS C:\> ,$tet | Get-Member
TypeName: System.Object[]
Name MemberType Definition
---- ---------- ----------
Count AliasProperty Count = Length
Address Method System.Object& Address(Int32 )
Clone Method System.Object Clone()
CopyTo Method System.Void CopyTo(Array array, Int32 i...
Equals Method System.Boolean Equals(Object obj)
Get Method System.Object Get(Int32 )
GetEnumerator Method System.Collections.IEnumerator GetEnume...
GetHashCode Method System.Int32 GetHashCode()
GetLength Method System.Int32 GetLength(Int32 dimension)
GetLongLength Method System.Int64 GetLongLength(Int32 dimens...
GetLowerBound Method System.Int32 GetLowerBound(Int32 dimens...
GetType Method System.Type GetType()
GetUpperBound Method System.Int32 GetUpperBound(Int32 dimens...
GetValue Method System.Object GetValue(Params Int32[] i...
get_IsFixedSize Method System.Boolean get_IsFixedSize()
get_IsReadOnly Method System.Boolean get_IsReadOnly()
get_IsSynchronized Method System.Boolean get_IsSynchronized()
get_Length Method System.Int32 get_Length()
get_LongLength Method System.Int64 get_LongLength()
get_Rank Method System.Int32 get_Rank()
get_SyncRoot Method System.Object get_SyncRoot()
Initialize Method System.Void Initialize()
Set Method System.Void Set(Int32 , Object )
SetValue Method System.Void SetValue(Object value, Int3...
ToString Method System.String ToString()
IsFixedSize Property System.Boolean IsFixedSize {get;}
IsReadOnly Property System.Boolean IsReadOnly {get;}
IsSynchronized Property System.Boolean IsSynchronized {get;}
Length Property System.Int32 Length {get;}
LongLength Property System.Int64 LongLength {get;}
Rank Property System.Int32 Rank {get;}
SyncRoot Property System.Object SyncRoot {get;}
Vajon miért nem ez az alapértelmezett működése a Get-Member -nek? A PowerShell alkotói próbáltak mindig olyan megoldásokat kitalálni, ami a gyakoribb felhasználási esetekre ad jó megoldást, márpedig inkább az a gyakoribb, hogy egy tömb elemeinek keressük a tagjellemzőit, nem pedig magának a tömbnek.
Van egy másik módszer is, amivel az „egész” objektum tagjellemzőit tudjuk megnézni:
[40] PS C:\> Get-Member -InputObject $tet
TypeName: System.Object[]
Name MemberType Definition
---- ---------- ----------
Count AliasProperty Count = Length
Address Method System.Object&, mscorlib, Version=2.0.0.0, Cul...
Clone Method System.Object Clone()
…
A fenti tagjellemzőkből nézzük meg a fontosabbakat:
[46] PS C:\> $tet.count # elemszám
4
[47] PS C:\> $tet.length # elemszám
4
[48] PS C:\> $tet.rank # dimenzió
1
[49] PS C:\> $tet.isfixedsize # fix méretű?
True
(A ’#’ jel megjegyzést jelöl, az ez utáni részt a parancsértelmező nem veszi figyelembe.) A fenti listában látjuk, hogy kétféle szintaxissal is lekérhetjük a tömb elemszámát, lekérhetjük, hogy hány dimenziós a tömb és hogy bővíthetjük-e a tömbünk elemszámát. Ez utóbbi szomorú eredményt ad, hiszen azt mondja, hogy ez fixméretű tömb, nem lehet elemeket hozzáadni. Vajon tényleg?
[54] PS C:\> $tet
1
2
3
4
[55] PS C:\> $tet += 11
[56] PS C:\> $tet
1
2
3
4
11
Azt láthatjuk, hogy az eredetileg négyelemű tömböt minden nehézség nélkül tudtuk öteleműre bővíteni a += operátorral. Ez azonban valójában nem ilyen egyszerűen ment végbe a felszín alatt, hanem a PowerShell létrehozott egy új, üres tömböt és szépen átmásolta az eredeti tömbünk elemeit, majd hozzábiggyesztette az új tagot. Természetesen ezt az új tömböt továbbra is a régi név alatt érjük el, de ez már valójában nem ugyanaz a tömb. Ez akkor érdekes, ha nagyon nagyméretű tömbökkel dolgozunk, hiszen akkor az új tömb felépítése során a művelet végrehajtásának végéig ideiglenesen kétszer is tárolódik a tömb, ami jelentős memória-felhasználást igényelhet.
Megjegyzés
Vigyázzunk a tömbök másolásakor! Merthogy a másolás valójában referencia alapján, azaz a memóriacím alapján történik a háttérben, azaz igazából ugyanaz a tömbünk van kétszer:
[1] PS C:\> $tömb1 = "a", "b", "c", "d"
[2] PS C:\> $tömb2 = $tömb1
[3] PS C:\> $tömb2
a
b
c
d
[4] PS C:\> $tömb1[0] = 1
[5] PS C:\> $tömb2
1
b
c
d
Azaz készítek egy tömböt [1], majd azt „átmásolom” egy másik változóba [2-3], majd módosítom az első tömb első elemét [4]. És mi történt? A második tömb első eleme is változott! [5]
Itt most kapóra jön nekünk viszont ennek a tömbtípusnak a „hiányossága”, azaz hogy nem lehet bővíteni, hanem az elem hozzáadása valójában új tömböt hoz létre:
[6] PS C:\> $tömb1 += "e"
[7] PS C:\> $tömb2
1
b
c
d
[8] PS C:\> $tömb1[0] = 2
[9] PS C:\> $tömb2
1
b
c
d
Látható, hogy mihelyst új elemet raktam az első tömbbe, az függetlenedett a másodiktól.
Most már csak egy dolgot nem mutattam meg, hogy hogyan lehet hivatkozni a tömbelem ekre:
[91] PS C:\> $scal[0] # első elem
1
[92] PS C:\> $scal[2..5] # harmadiktól hatodik elemig
3
4
5
200
[93] PS C:\> $scal[5..2] # hatodiktól harmadik elemig
200
5
4
3
A fenti példákban látható, hogy a tömbök első elemére a 0-s indexszel lehet hivatkozni. Egyszerre több egymás utáni elemre a (.. ) range , azaz tartomány operátorral. Ugyan operátorokkal később foglalkozom, de ez a „range” operátor annyira kötődik a tömbökhöz, hogy érdemes itt tárgyalni. Az alábbi példa mutatja az alapvető működését:
[94] PS C:\> 1..10
1
2
3
4
5
6
7
8
9
10
A range segítségével egy másik, érdekes módon is lehet hivatkozni a tömbelemekre, de az csak a „hagyományos” array-re működik:
[95] PS C:\> $a=1,2,3,4,10,8
[96] PS C:\> $a
1
2
3
4
10
8
[97] PS C:\> $a[-1..-3]
8
10
4
A [97]-es prompt azt mutatja, hogy értelmezett a negatív index, amit a PowerShell a tömb utolsó elemétől visszafele számol. A -1. elem az utolsó elem, -2. az utolsó előtti és így tovább.
Ha több elem kellene egyszerre? Adjunk meg bátran több indexet egyszerre! Ebben az esetben természetesen a visszakapott érték is egy tömb lesz.
PS C:\> $b = 1..100
PS C:\> $b[5,7,56]
6
8
57
Az már csak hab a tortán, hogy nemcsak konkrét indexet, hanem intervallumot (sőt akár több intervallumot) adhatunk meg ebben az esetben is.
PS C:\> $b = 1..100
PS C:\> $b[2..4 + 56..58]
3
4
5
57
58
59
Megjegyzés
PowerShell 3.0-tól kezdve már az alapértelmezett tömb is kicsit „okosabb”, mint a korábban látható 2.0-ás tömb:
PS C:\> Get-Member -InputObject (1,2)
TypeName: System.Object[]
Name MemberType Definition
---- ---------- ----------
Count AliasProperty Count = Length
Add Method int IList.Add(System.Object value)
Address Method System.Object&, mscorlib, Version=4.0....
Clear Method void IList.Clear()
Clone Method System.Object Clone(), System.Object I...
CompareTo Method int IStructuralComparable.CompareTo(Sy...
Contains Method bool IList.Contains(System.Object value)
CopyTo Method void CopyTo(array array, int index), v...
Equals Method bool Equals(System.Object obj), bool I...
Get Method System.Object Get(int )
GetEnumerator Method System.Collections.IEnumerator GetEnum...
GetHashCode Method int GetHashCode(), int IStructuralEqua...
GetLength Method int GetLength(int dimension)
GetLongLength Method long GetLongLength(int dimension)
GetLowerBound Method int GetLowerBound(int dimension)
GetType Method type GetType()
GetUpperBound Method int GetUpperBound(int dimension)
GetValue Method System.Object GetValue(Params int[] in...
IndexOf Method int IList.IndexOf(System.Object value)
Initialize Method void Initialize()
Insert Method void IList.Insert(int index, System.Ob...
Remove Method void IList.Remove(System.Object value)
RemoveAt Method void IList.RemoveAt(int index)
Set Method void Set(int , System.Object )
SetValue Method void SetValue(System.Object value, int...
ToString Method string ToString()
Item ParameterizedProperty System.Object IList.Item(int index) {g...
IsFixedSize Property bool IsFixedSize {get;}
IsReadOnly Property bool IsReadOnly {get;}
IsSynchronized Property bool IsSynchronized {get;}
Length Property int Length {get;}
LongLength Property long LongLength {get;}
Rank Property int Rank {get;}
SyncRoot Property System.Object SyncRoot {get;}
Látható, hogy kibővült a metódusok listája az Add és a Remove-al, ami hatékonyabbá teszi a tömbök bővítését a += operátor használatához képest.
A .NET Frameworkben van az előzőekben látott [system.object[]]-nél többfajta „okosabb” tömb is, melyeket különböző célokra használhatjuk PowerShellben. Az egyik ilyen a System.Collections.ArrayList típus, mely leginkább hasonlít az egyszerű tömbre. Nézzük meg ennek a tagjellemzőit:
PS C:\> $scal = New-Object system.collections.arraylist
PS C:\> gm -InputObject $scal
TypeName: System.Collections.ArrayList
Name MemberType Definition
---- ---------- ----------
Add Method int Add(System.Object value), int IL...
AddRange Method void AddRange(System.Collections.ICo...
BinarySearch Method int BinarySearch(int index, int coun...
Clear Method void Clear(), void IList.Clear()
Clone Method System.Object Clone(), System.Object...
Contains Method bool Contains(System.Object item), b...
CopyTo Method void CopyTo(array array), void CopyT...
Equals Method bool Equals(System.Object obj)
GetEnumerator Method System.Collections.IEnumerator GetEn...
GetHashCode Method int GetHashCode()
GetRange Method System.Collections.ArrayList GetRang...
GetType Method type GetType()
IndexOf Method int IndexOf(System.Object value), in...
Insert Method void Insert(int index, System.Object...
InsertRange Method void InsertRange(int index, System.C...
LastIndexOf Method int LastIndexOf(System.Object value)...
Remove Method void Remove(System.Object obj), void...
RemoveAt Method void RemoveAt(int index), void IList...
RemoveRange Method void RemoveRange(int index, int count)
Reverse Method void Reverse(), void Reverse(int ind...
SetRange Method void SetRange(int index, System.Coll...
Sort Method void Sort(), void Sort(System.Collec...
ToArray Method System.Object[] ToArray(), array ToA...
ToString Method string ToString()
TrimToSize Method void TrimToSize()
Item ParameterizedProperty System.Object Item(int index) {get;s...
Capacity Property int Capacity {get;set;}
Count Property int Count {get;}
IsFixedSize Property bool IsFixedSize {get;}
IsReadOnly Property bool IsReadOnly {get;}
IsSynchronized Property bool IsSynchronized {get;}
SyncRoot Property System.Object SyncRoot {get;}
Itt már egész fejlett lehetőségeket találunk. Van itt Add metódus, amivel lehet egy elemet hozzáadni, az AddRange-el meg sok elemet, meg van Contains, amivel lehet megvizsgálni, hogy egy adott érték benne van-e a tömbben, az Insert metódussal be lehet szúrni elemeket, a Remove-val el lehet távolítani egy elemet annak értéke alapján, vagy a RemoveAt-tel pozíció alapján, a Reverse-zel meg lehet fordítani az elemek sorrendjét, a Sort-tal sorba lehet rendezni:
[67] PS C:\> $scal = [system.collections.arraylist] (1,2,3,4,5)
[68] PS C:\> $scal
1
2
3
4
5
[69] PS C:\> $scal.Contains(4)
True
[70] PS C:\> $scal.add(1000)
5
[71] PS C:\> $scal
1
2
3
4
5
1000
[72] PS C:\> $scal.insert(3, 200)
[73] PS C:\> $scal
1
2
3
200
4
5
1000
[74] PS C:\> $scal.reverse()
[75] PS C:\> $scal
1000
5
4
200
3
2
1
[76] PS C:\> $scal.sort()
[77] PS C:\> $scal
1
2
3
4
5
200
1000
Az Add-nél vigyázni kell, hogy kimenetet ad, méghozzá azt a számot, ahanyadik elemként tette hozzá az éppen hozzáadott elemet. Ha ez nem kell, akkor el lehet „fojtani” a kimenetet az alábbi két módszer valamelyikével:
[78] PS C:\> [void] $scal.add(1234)
[79] PS C:\> $scal.add(2345) > $null
A [78]-es promptban átkonvertáljuk a kimenetet [void] típussá, azaz semmivé. A [79]-as sorban pedig átirányítjuk a semmibe a kimenetet.
Megjegyzés
Nem mindegy, hogy hogyan adunk elemet egy ilyen „okos” tömbhöz. Az előző megjegyzésben láthattuk, hogy a tömbök másolása változók között valójában csak a tömb címét másolja, mindkét változó ugyanarra a tömbre mutat. Ugyanez igaz a collections.arraylist tömbre is. Ez az ugyanoda mutatás megszűnik, ha a += operátorral bővítem a tömböt, viszont nem szűnik meg, ha az Add() metódust használjuk:
PS C:\> $ot1 = [collections.arraylist] (1,2,3,4,5)
PS C:\> $ot2 = $ot1
PS C:\> $ot1[0]="a"
PS C:\> $ot2
a
2
3
4
5
PS C:\> $ot1 += 6
PS C:\> $ot2
a
2
3
4
5
PS C:\> $ot1.GetType().FullName
System.Object[]
A fenti példában látható, hogy míg az „a” érték beadása a 0. elemként mind az $ot1, mind at $ot2-re érvényes volt, addig a $ot1 +=-vel történő bővítése után az már egy másik tömb lett $ot2-höz képest, a típusa is átváltozott System.Object[]-re.
Ezzel szemben, ha az Add metódust használjuk, minden marad az eredeti típusban és a két változó közti referencia is megmarad:
PS C:\> $ot1 = [collections.arraylist] (1,2,3,4,5)
PS C:\> $ot2 = $ot1
PS C:\> $ot1.add(6)
5
PS C:\> $ot2
1
2
3
4
5
6
PS C:\> $ot1.GetType().FullName
System.Collections.ArrayList
Az arraylist-nek van még bináris keresője is! Ha sorrendben tartjuk benne az elemeket, akkor a binarysearch nagyon gyorsan megadja azt az indexet, ahol az elem található. Ha nincs benne, akkor azt a negatív számot adja meg, aminek ellentettjéből kivonva egyet lenne az az index, ahol az elemnek lennie kéne:
PS C:\> $bs = [collections.arraylist] (1..20 + 22..40)
PS C:\> $bs.BinarySearch(20)
19
PS C:\> $bs.BinarySearch(21)
-21
A fenti példában csináltam egy számsort 1-től 40-ig, amiből hiányzik a 21-es érték. A BinarySearch a 20-ra megadja a 19-es index értéket, a 21-re viszont -21-et ad, aminek ellentettjének egyel kevesebb értéke 20, itt lenne a 21, illetve ide lehet berakni, ha az lenne a feladat:
PS C:\> $bs.Insert(20,21)
Az ArrayList elemei indexelhetők:
PS C:\> $bs[5]
6
Ezt azért fontos hangsúlyozni, mert a következő két tömbtípusnál csak egy bizonyos elemet lehet megnézni vagy kivenni, viszont bizonyos célokra pont erre lehet szükségünk.
A következő speciális tömbváltozat a [systems.collections.queue] sor:
PS C:\> $queue = [System.Collections.Queue] @()
PS C:\> Get-Member -InputObject $queue
TypeName: System.Collections.Queue
Name MemberType Definition
---- ---------- ----------
Clear Method void Clear()
Clone Method System.Object Clone(), System.Object ICloneable...
Contains Method bool Contains(System.Object obj)
CopyTo Method void CopyTo(array array, int index), void IColl...
Dequeue Method System.Object Dequeue()
Enqueue Method void Enqueue(System.Object obj)
Equals Method bool Equals(System.Object obj)
GetEnumerator Method System.Collections.IEnumerator GetEnumerator(),...
GetHashCode Method int GetHashCode()
GetType Method type GetType()
Peek Method System.Object Peek()
ToArray Method System.Object[] ToArray()
ToString Method string ToString()
TrimToSize Method void TrimToSize()
Count Property int Count {get;}
IsSynchronized Property bool IsSynchronized {get;}
SyncRoot Property System.Object SyncRoot {get;}
A metódusaiból látható, hogy az Enqueue-val lehet elemeket berakni, Peek-el lehet belekukucskálni, hogy melyik az az elem, ami kivétel szempontjából a következő lesz a sorban, Dequeue-val lehet kivenni a legkorábban berakott elemet:
PS C:\> $queue.Enqueue(1)
PS C:\> $queue.Enqueue("a")
PS C:\> $queue.Enqueue(2)
PS C:\> $queue.Enqueue("b")
PS C:\> $queue.Peek()
1
PS C:\> $queue
1
a
2
b
PS C:\> $queue.Dequeue()
1
PS C:\> $queue
a
2
b
Azaz ez egy FIFO (first in, first out) sor. Ha olyan feladatunk van, amiben a sorrendtartó elemkezelés fontos, akkor ez a típus jó szolgálatot tehet.
Egy másik tömbváltozat a [system.collections.stack] zsák. Ennek az a jellegzetessége, hogy pont fordított módon működik a sorhoz képeset, azaz FILO (first in, last out) módon:
PS C:\> $stack = [System.Collections.Stack] @()
PS C:\> Get-Member -InputObject $stack
TypeName: System.Collections.Stack
Name MemberType Definition
---- ---------- ----------
Clear Method void Clear()
Clone Method System.Object Clone(), System.Object ICloneable...
Contains Method bool Contains(System.Object obj)
CopyTo Method void CopyTo(array array, int index), void IColl...
Equals Method bool Equals(System.Object obj)
GetEnumerator Method System.Collections.IEnumerator GetEnumerator(),...
GetHashCode Method int GetHashCode()
GetType Method type GetType()
Peek Method System.Object Peek()
Pop Method System.Object Pop()
Push Method void Push(System.Object obj)
ToArray Method System.Object[] ToArray()
ToString Method string ToString()
Count Property int Count {get;}
IsSynchronized Property bool IsSynchronized {get;}
SyncRoot Property System.Object SyncRoot {get;}
A metódusai hasonlóak a soréhoz, csak itt Push-sal teszünk be elemet, Pop-pal vesszük ki, de ugyanúgy Peek-kel nézünk bele:
PS C:\> $stack.Push(1)
PS C:\> $stack.Push("a")
PS C:\> $stack.Push(2)
PS C:\> $stack.Push("b")
PS C:\> $stack.Peek()
b
PS C:\> $stack
b
2
a
1
PS C:\> $stack.Pop()
b
PS C:\> $stack
2
a
1
Ezt olyan esetekben célszerű használni, ahol épp mindig a legutóbb berakott elemekre van szükségünk.
Megjegyzés
Természetesen nem csak Peek-el lehet belenézni a queue-ba és a stack-be, hanem kilistázhatjuk az összes elemüket is, ahogy a fenti példában láttuk:
PS C:\> $queue
1
a
2
b
és
PS C:\> $stack
b
2
a
1
De indexelni nem tudunk.
Természetesen egy tömbnek nem csak egyirányú kiterjedése lehet, tudunk többdimenziós tömböket is létrehozni. Az alábbi példában úgy érem el a kétirányú kiterjedést, hogy a $tábla tömb elemeiként szintén tömböket teszek (ahogy korábban már láttuk a $tömböktömbje példában):
[1] PS C:\> $tábla = (1,2,3,4),("a","b","c","d")
[2] PS C:\> $tábla
1
2
3
4
a
b
c
d
[3] PS C:\> $tábla[0][0]
1
[4] PS C:\> $tábla[0][1]
2
[5] PS C:\> $tábla[1][0]
a
Látszik, hogy ilyenkor két indexszel hivatkozhatunk a „dimenziókra”. Sőt! Nem csak egyforma „hosszú” sorokból állhat egy „kvázi” kétdimenziós tömb:
[7] PS C:\> $vegyes = (1,2,3),("a","b"),("egy","kettő","három","négy")
[8] PS C:\> $vegyes[0][0]
1
[9] PS C:\> $vegyes[0][2]
3
[10] PS C:\> $vegyes[0][3]
[11] PS C:\> $vegyes[1][1]
b
[12] PS C:\> $vegyes[1][2]
[13] PS C:\> $vegyes[2][3]
négy
Az „igazi” többdimenziós tömböt az alábbi szintaxissal lehet hivatalosan létrehozni, és ilyenkor másként kell hivatkozni a tömbelemekre:
[20] PS C:\> $igazi = new-object -TypeName 'object[,]' -ArgumentList 3,2
[21] PS C:\> $igazi[2,1]="kakukk"
Természetesen nem csak kettő, hanem akárhány dimenziós lehet egy tömb, de ilyet valószínű csak a robottechnikában használnak. Példa egy tízdimenziós tömbre:
[23] PS C:\> $igazi = new-object 'object[,,,,,,,,,]' 8,3,7,5,6,7,8,9,10,3
Mik az előnyei az „igazi” többdimenziós tömbök használatának? Egyrészt biztosak lehetünk benne, hogy minden sorban ugyanannyi elem van. Másrészt az elemekre történő hivatkozásnál elég akár egy darab változót használni az elemek címzésére. Nézzünk erre egy példát:
PS C:\> $igazi = new-object -TypeName 'object[,]' -ArgumentList 5,4
PS C:\> $x = 1; $y = 2; $igazi[$x,$y] = "kakukk"
Az $igazi itt most egy 5*4-es tömb, két változóval, az $x és $y-al hivatkozok az egyik elemre, ahova betöltöm a „kakukk” szöveget. Viszont kihasználhatjuk, hogy valójában a többdimenziós tömböknél az index az valójában egy tömb (vesszővel elválasztott értékek), azaz létrehozhatunk egy összetett index-változót is:
PS C:\> $komplexindex = 1,2
PS C:\> $igazi[$komplexindex]
Kakukk
Ez természetesen akárhány dimenziós tömböknél is működik, csak figyelni kell, hogy az index-változónkban pont annyi elem legyen, ahány dimenziós a tömbünk.
Tudunk létrehozni típusos tömböket , amelyek csak az adott típusú elemeket tartalmazhatnak:
[24] PS C:\> $t = New-Object int[] 20
[25] PS C:\> $t[1]="szöveg"
Array
assignment to [1] failed: Cannot convert value "szöveg" to type
"Sy
stem.Int32".
Error: "Input string was not in a correct format.".
At line:1
char:4
+ $t[
<<<< 1]="szöveg"
+ CategoryInfo : InvalidOperation: (szöveg:String)
[], Runt
imeException
+ FullyQualifiedErrorId :
ArrayAssignmentFailed
[26] PS C:\> $t += 2
A fenti példában látszik, hogy létrehozunk előre egy 20 elemű int típusú tömböt, amibe ha szöveget akarunk betölteni, akkor hibát kapunk. Azonban ha új elemet biggyesztünk hozzá, akkor az már lehet akármilyen típusú.
Természetesen típusos tömbökből többdimenziósakat is létre tudunk hozni:
[27] PS C:\> $ttdt = New-Object 'int[,]' 5,2
[28] PS C:\> $ttdt[0,0] = 12
[29] PS C:\> $ttdt[1,1] = "próba"
Array
assignment to [1,1] failed: Cannot convert value "próba" to type
"System
.Int32".
Error: "Input string was not in a correct format.".
At line:1
char:7
+ $ttdt[
<<<< 1,1] = "próba"
+ CategoryInfo : InvalidOperation: (próba:String)
[], RuntimeExc
eption
+ FullyQualifiedErrorId :
ArrayAssignmentFailed
Itt tehát annyi a különbség, hogy nem általános object-ek a tömb elemei, hanem itt a példában int típus. A [29]-es sorban nem is szerette, ha sztringet akartam beletenni.
A .NET keretrendszer tartalmaz egy olyan tömböt, aminek paraméterként adható át, hogy milyen elemeket tartalmazhasson:
PS C:\> $type = "string"
PS C:\> $genlist = New-Object "collections.generic.list[$type]"
PS C:\> get-member -InputObject $genlist
TypeName: System.Collections.Generic.List`1[[System.String, mscorlib, Versi
on=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
Name MemberType Definition
---- ---------- ----------
Add Method void Add(string item), void ICollectio...
AddRange Method void AddRange(System.Collections.Gener...
AsReadOnly Method System.Collections.ObjectModel.ReadOnl...
BinarySearch Method int BinarySearch(int index, int count,...
Clear Method void Clear(), void ICollection[string]...
Contains Method bool Contains(string item), bool IColl...
ConvertAll Method System.Collections.Generic.List[TOutpu...
CopyTo Method void CopyTo(string[] array), void Copy...
Equals Method bool Equals(System.Object obj)
Exists Method bool Exists(System.Predicate[string] m...
Find Method string Find(System.Predicate[string] m...
FindAll Method System.Collections.Generic.List[string...
FindIndex Method int FindIndex(System.Predicate[string]...
FindLast Method string FindLast(System.Predicate[strin...
FindLastIndex Method int FindLastIndex(System.Predicate[str...
ForEach Method void ForEach(System.Action[string] act...
GetEnumerator Method System.Collections.Generic.List`1+Enum...
GetHashCode Method int GetHashCode()
GetRange Method System.Collections.Generic.List[string...
GetType Method type GetType()
IndexOf Method int IndexOf(string item), int IndexOf(...
Insert Method void Insert(int index, string item), v...
InsertRange Method void InsertRange(int index, System.Col...
LastIndexOf Method int LastIndexOf(string item), int Last...
Remove Method bool Remove(string item), bool ICollec...
RemoveAll Method int RemoveAll(System.Predicate[string]...
RemoveAt Method void RemoveAt(int index), void IList[s...
RemoveRange Method void RemoveRange(int index, int count)
Reverse Method void Reverse(), void Reverse(int index...
Sort Method void Sort(), void Sort(System.Collecti...
ToArray Method string[] ToArray()
ToString Method string ToString()
TrimExcess Method void TrimExcess()
TrueForAll Method bool TrueForAll(System.Predicate[strin...
Item ParameterizedProperty string Item(int index) {get;set;}
Capacity Property int Capacity {get;set;}
Count Property int Count {get;}
IsFixedSize Property bool IsFixedSize {get;}
IsReadOnly Property bool IsReadOnly {get;}
IsSynchronized Property bool IsSynchronized {get;}
SyncRoot Property System.Object SyncRoot {get;}
Látható, hogy a $genlist objektum létrehozásakor meghatároztam, hogy ez egy olyan típusú tömb legyen, amelynek elemei sztringek lehetnek. Ha kilistázom a tagjellemzőit ennek az objektumnak, akkor láthatjuk, hogy ez is „okos” tömb, azaz itt is van Add() metódus és sok más hasznos dolog.
A típusos tömbök egy különleges fajtája a halmaz . A .NET-ben ennek a típusnak teljes neve: System.Collections.Generic.HashSet . Nem tévesztendő össze ez a hashtable adattípussal (ld. a következő fejezetben)!
A halmaz olyan típusos tömb, amiben az elemek egyedieknek kell lenniük.
PS C:\> $set = [System.Collections.Generic.HashSet[string]] ('egy', 'kettő', 'h
árom')
PS C:\> $set
egy
kettő
három
A fenti $set tehát tartalmaz három sztringet. Ha hozzá akarjuk adni újra az ’egy’-et, akkor az Add() metódus eredménye $false-t ad:
PS C:\> $set.Add('egy')
False
Csináljunk egy másik halmazt most a New-Object segítségével és már a kezdeti elemeket is az Add()-el adom meg:
PS C:\> $másik = New-Object System.Collections.Generic.HashSet[string]
PS C:\> $másik.add('egy')
True
PS C:\> $másik.add('négy')
True
A halmazok által nyújtott előnyök a metódusokban találhatók a halmazműveletek képében:
PS C:\> Get-Member -InputObject $másik
TypeName: System.Collections.Generic.HashSet`1[[System.String, mscorlib, Ve
rsion=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
Name MemberType Definition
---- ---------- ----------
Add Method bool Add(string item), void ICollection[stri...
Clear Method void Clear(), void ICollection[string].Clear()
Contains Method bool Contains(string item), bool ICollection...
CopyTo Method void CopyTo(string[] array, int arrayIndex),...
Equals Method bool Equals(System.Object obj)
ExceptWith Method void ExceptWith(System.Collections.Generic.I...
GetEnumerator Method System.Collections.Generic.HashSet`1+Enumera...
GetHashCode Method int GetHashCode()
GetObjectData Method void GetObjectData(System.Runtime.Serializat...
GetType Method type GetType()
IntersectWith Method void IntersectWith(System.Collections.Generi...
IsProperSubsetOf Method bool IsProperSubsetOf(System.Collections.Gen...
IsProperSupersetOf Method bool IsProperSupersetOf(System.Collections.G...
IsSubsetOf Method bool IsSubsetOf(System.Collections.Generic.I...
IsSupersetOf Method bool IsSupersetOf(System.Collections.Generic...
OnDeserialization Method void OnDeserialization(System.Object sender)...
Overlaps Method bool Overlaps(System.Collections.Generic.IEn...
Remove Method bool Remove(string item), bool ICollection[s...
RemoveWhere Method int RemoveWhere(System.Predicate[string] match)
SetEquals Method bool SetEquals(System.Collections.Generic.IE...
SymmetricExceptWith Method void SymmetricExceptWith(System.Collections....
ToString Method string ToString()
TrimExcess Method void TrimExcess()
TryGetValue Method bool TryGetValue(string equalValue, [ref] st...
UnionWith Method void UnionWith(System.Collections.Generic.IE...
Comparer Property System.Collections.Generic.IEqualityComparer...
Count Property int Count {get;}
IsReadOnly Property bool IsReadOnly {get;}
Nézzük ezeket a halmazműveleteket! Ezek eredményei mindig abba a halmazba kerülnek, amelyen meghívjuk ezeket, azaz az eredeti halmaz felülíródik. Az UnionWith() az unióképzés, azaz a két halmaz egyesítése:
PS C:\> $set.UnionWith($másik); $set
egy
kettő
három
négy
A két egyesített halmaz elemei egyszer szerepelnek az eredményben.
Újra töltöm az eredeti elemekkel a $set-et, nézzük így meg, hogy mit az az IntersectWith(), azaz a metszet:
PS C:\> $set = [System.Collections.Generic.HashSet[string]] ('egy', 'kettő', 'h
árom')
PS C:\> $set.IntersectWith($másik); $set
egy
Itt az eredmény a két halmaz közös elemeiből áll.
Újra töltés után nézzük az ExceptWith()-et, azaz a halmazok különbségét:
PS C:\> $set = [System.Collections.Generic.HashSet[string]] ('egy', 'kettő', 'h
árom')
PS C:\> $set.ExceptWith($másik); $set
kettő
három
Itt az eredeti halmazban azok az elemek maradnak, amik nincsenek benne a metszetben. Ezekkel tulajdonképpen meg is elégedhetnénk, de van még egy: SymmetricExceptWith() adja az unióból kivett metszetet:
PS C:\> $set = [System.Collections.Generic.HashSet[string]] ('egy', 'kettő', 'h
árom')
PS C:\> $set.SymmetricExceptWith($másik); $set
négy
kettő
három
Van még ezeken kívül jónéhány vizsgálatot végző metódus is, amelyekkel azt lehet megnézni, hogy az egyik halmaz tartalmazza-e a másikat.