none
Dynamisches zweidimensional Array aus Funktion RRS feed

  • Frage

  • Hallo zusammen,

    ich habe eine Frage bzw komme mit einer Idee nicht weiter.

    In einer Funktion möchte ich ein zweidimensionales Array erstellen und über eine Schleife dynamisch erweitern. Das so erstellte Array müchte ich dann aus der Funktion als Objekt (?) zurück geben.

    Ziel ist das ich in einer Schleife alle *.xml Files aus einem Verzeichnis auslese und den Inhalt mit Dateinamen im Array ablege, also quasi

    @('test.xml','<spielfilme><film regie="Tom Tykwer" titel="Lola rennt"><beschreibung><name typ="w">Lola</name> rennt für <name typ="m">Manni</name>, der 100000 Mark liegengelassen hat und noch 20 Minuten Zeit hat, das Geld auszuliefern.</beschreibung></film></spielfilme>')

    und so weiter.

    Wenn ich 5 XML-Files finde, so müsste im Array 5 Datensätze erfasst sein mit Datei-Name und -Inhalt.

    Ich müsste also in der Funktion ein leeres Array erstellen, dann in der Schleife befüllen, das Array aus der Funktion zurückgeben und im Hauptscipt dann $ergebnis=funktionsname verwenden da Powershell damit ja die Variablen-Typ richtig setzt.

    Verstehe ich das so richtig?

    Gruss,
    Daniel

    PS: Ich hatte bisher mit Visual Basic zu tun, daher entschuldigt bitte wen ich was doofes Frage :-)

    • Bearbeitet DniBo Dienstag, 10. Dezember 2019 09:56
    Dienstag, 10. Dezember 2019 09:44

Antworten

  • Wenn Du von VB kommst, hast Du ja etwas Programmiererfahrung. Ich würde Arrays gleich wieder vergessen - besser ist System.Collections.ArrayList (oder ein anderes der Collection-Objekte).

    Mein persönlicher Favorite ist eine Arraylist, die ich mit [PSCustomObject]@{Name='Hashtable';Value='Schaumaleineran';Irgendwas=@{Child1='ErstesKind';Child2='ZweitesKind'}} fülle. Da habe ich vollständige Flexibilität bei quasi allem :-) Und die einzelnen Properties der Hashtables können natürlich ihrerseits auch wieder alles mögliche sein - Arrays, Arraylists oder sogar nested Hashtables.


    Greetings/Grüße, Martin - https://mvp.microsoft.com/en-us/PublicProfile/5000017 Mal ein gutes Buch über GPOs lesen? - http://www.amazon.de/Windows-Server-2012--8-Gruppenrichtlinien/dp/3866456956 Good or bad GPOs? My blog - http://evilgpo.blogspot.com And if IT bothers me? Coke bottle design refreshment - http://sdrv.ms/14t35cq

    Dienstag, 10. Dezember 2019 11:31
  • Also wenn das XML ist, dann würde ich das jeweils in ein XML-Objekt stecken und diese dann in eine ArrayList packen. Und wenn Du in die ArrayList ne Hashtable packst, bei der eine der Properties dann als Wert das XML enthält -> voila...

    $AllFiles = Foreach ( $xmlfile in Get-Item *.xml ) {
        [PSCustomObject]@{
            Name = $xmlfile.Name
            Content = [xml]( Get-Content $xmlFile )
        }
    }
    Sinngemäß... Oder etwas anders dann mit der ArrayList oder xyz. Letzlich ist es ja Dein Code, Du mußt eine Variante finden, die Dir liegt.

    Greetings/Grüße, Martin - https://mvp.microsoft.com/en-us/PublicProfile/5000017 Mal ein gutes Buch über GPOs lesen? - http://www.amazon.de/Windows-Server-2012--8-Gruppenrichtlinien/dp/3866456956 Good or bad GPOs? My blog - http://evilgpo.blogspot.com And if IT bothers me? Coke bottle design refreshment - http://sdrv.ms/14t35cq

    Dienstag, 10. Dezember 2019 17:14

Alle Antworten

  • Hast du denn schon etwas code? Was genau funktioniert nicht?

    Im Prinzip musst du nur ein leeres Array erzeugen und dieses dann über eine Schleife befüllen.

    Powershell ist Objektbasiert. Wenn du dem Array also die XMLs übergibst, hast du ein Array das mit Objekten befüllt ist. Dem entsprechend kannst du dann auf jedes Objekt des Arrays zugreifen und mit dem Objekt oder dessen Attributen weiter arbeiten.

    Gruß


    Dienstag, 10. Dezember 2019 10:19
  • Hi,

    hiermit erstelle ich ja quasi schon ein Array:

    $xmllist = $xmllist + "Erster Satz","Erster Inhalt"
    $xmllist = $xmllist + "Zweiter Satz","Zweiter Inhalt" $xmllist = $xmllist + "Dritter Satz","Dritter Inhalt" $xmllist = $xmllist + "Vierter Satz","Vierter Inhalt" $xmllist = $xmllist + "Fünfter Satz","Fünfter Inhalt"

    Wie aber erstelle ich ein leeres Array (ohne Vorgabe der Grösse) für das zweidimensionale Array mit Werte für Datei-Name und den XML-Inhalt?

    Mit $xmlist = New-Object -TypeName "String[,]" ging es nicht, hätte ich so gedacht das es gehen sollte.

    Gruss,
    Daniel


    • Bearbeitet DniBo Dienstag, 10. Dezember 2019 10:49
    Dienstag, 10. Dezember 2019 10:41
  • Ein leeres Array erzeugst du mit 

    $xmllist=@()

    Objekte Kannst du mit 

    +=

    an das Array übergeben.

    Gruß

    Dienstag, 10. Dezember 2019 11:00
  • Wenn Du von VB kommst, hast Du ja etwas Programmiererfahrung. Ich würde Arrays gleich wieder vergessen - besser ist System.Collections.ArrayList (oder ein anderes der Collection-Objekte).

    Mein persönlicher Favorite ist eine Arraylist, die ich mit [PSCustomObject]@{Name='Hashtable';Value='Schaumaleineran';Irgendwas=@{Child1='ErstesKind';Child2='ZweitesKind'}} fülle. Da habe ich vollständige Flexibilität bei quasi allem :-) Und die einzelnen Properties der Hashtables können natürlich ihrerseits auch wieder alles mögliche sein - Arrays, Arraylists oder sogar nested Hashtables.


    Greetings/Grüße, Martin - https://mvp.microsoft.com/en-us/PublicProfile/5000017 Mal ein gutes Buch über GPOs lesen? - http://www.amazon.de/Windows-Server-2012--8-Gruppenrichtlinien/dp/3866456956 Good or bad GPOs? My blog - http://evilgpo.blogspot.com And if IT bothers me? Coke bottle design refreshment - http://sdrv.ms/14t35cq

    Dienstag, 10. Dezember 2019 11:31
  • Hallo zusammen,

    irgendwann schaffe ich den Sprung zu PowerShell :-)

    @Marc: Dann bedeutet es unabhängig ob ein oder mehrdimensional, man legt ein Array immer mit "$xmllist@()" an?

    @Marting: Das Beispiel mit "[PSCustomObject]@" liest sich interessant, werde ich mehr vertiefen. Wie lege ich hier ein leeres Array an, auch mit "[PSCustomObject]@()" um dann zweidimensional weiter zu machen?

    Ziel ist das Object in der Function zu erstellen, aus der Function zurück zu geben und in der Function wieder zu zerstören, nicht das mir bei extensiver Verwendung das RAM um die Ohren fliegt.


    Viele Grüsse,
    Daniel


    • Bearbeitet DniBo Dienstag, 10. Dezember 2019 12:40
    Dienstag, 10. Dezember 2019 12:38
  • Daniel,

    üblicherweise erstellen wir in Powershell keine leeren Arrays. Das ist normalerweise einfach nicht nötig. Vielleicht erklärst Du mal etwas genauer, was Du eigentlich machen möchtest. Manche von anderen Script- oder Programmiersprachen gebräuchlichen Techniken sind in Powershell unnötig oder manchmal sogar kontraproduktiv.  ;-)


    Live long and prosper!

    (79,108,97,102|%{[char]$_})-join''

    Dienstag, 10. Dezember 2019 13:10
  • üblicherweise erstellen wir in Powershell keine leeren Arrays.

    $MyCollection = New-Object -TypeName System.Collections.ArrayList
    [void]$MyCollection.Add( [PSCustomObject]@{ Titel='Lola rennt';  Regie='Tom Tywker' } )


    Greetings/Grüße, Martin - https://mvp.microsoft.com/en-us/PublicProfile/5000017 Mal ein gutes Buch über GPOs lesen? - http://www.amazon.de/Windows-Server-2012--8-Gruppenrichtlinien/dp/3866456956 Good or bad GPOs? My blog - http://evilgpo.blogspot.com And if IT bothers me? Coke bottle design refreshment - http://sdrv.ms/14t35cq

    Dienstag, 10. Dezember 2019 15:02
  • Hi,

    ok, was will ich erreichen :-)

    Ich möchte verschiedene ZIP-Files auf dem File-Server auslesen und die darin enthaltenen XML-Dateien erfassen/lesen. Hier handelt es sich ausschliesslich um Files einer unserer Applikationen, diese kann ich entsprechend selektieren und eingrenzen.

    Für mein Verständnis (und weil ich einige andere Funktionen haben werde), möchte ich das auslesen pro ZIP-File in einer Funktion realisieren und das Array aus der Funktion zurück geben.

    Ein leeres Array möchte ich deshalb erstellen um dann in einer Schleife den Inhalt aller gefundenen XML-Files abzulegen.

    Der Aufbau soll so sein das im ersten Feld der Dateiname steht (z.Bsp. test.xml), im zweiten Feld dann der Inhalt des XML-File (wie im Beispiel ganz oben), das dann pro Datei ein Datensatz im Array.

    Ist das ZIP-File komplett ausgelesen, gebe ich das erstellte Array als Object zurück und lösche das Array mit dispose um aufzuräumen.

    In VB würde ich das so machen und sehe die Funktionen quasi als eigenständige Abläufe für sich.

    Da ich zum einen Powershell sehr mächtig finde und das Script dann auch für Kollegen lesbar bzw anpassbar ist, schwenke ich von VB auf Powershell, zumal ich Powershell schon bei kleinen Dingen sehr mächtig finde.

    Hoffe ich habe es so verständlich erklärt :-)

    Viele Grüsse,
    Daniel

    Dienstag, 10. Dezember 2019 15:07

  • Ziel ist das ich in einer Schleife alle *.xml Files aus einem Verzeichnis auslese und den Inhalt mit Dateinamen im Array ablege, also quasi

    @('test.xml','<spielfilme><film regie="Tom Tykwer" titel="Lola rennt"><beschreibung><name typ="w">Lola</name> rennt für <name typ="m">Manni</name>, der 100000 Mark liegengelassen hat und noch 20 Minuten Zeit hat, das Geld auszuliefern.</beschreibung></film></spielfilme>')

    und so weiter.

    Wenn ich 5 XML-Files finde, so müsste im Array 5 Datensätze erfasst sein mit Datei-Name und -Inhalt.


    Also wenn das der Task ist, dann kannst du auch einfach die XMLs direkt an ein Array übergeben und danach auf die Objekte zugreifen.

    $xml = get-childitem *.xml

    Und mit 

    Get-Content ($xml.name -eq "test.xml")

    kannst du dann z.B. auf den Inhalt der gewünschten XML zugreifen. Oder eben auch auf alle anderen Attribute der Objekte.

    Dafür braucht es also keine Schleifen und Funktionen.

    Gruß

    Dienstag, 10. Dezember 2019 15:16
  • Das ist bereits oben beschrieben:

    $Arr = @() <= Entspricht einer ArrayList

    $Arr += $Obj1
    $Arr += $Obj2

    $Arr[n] <= $Objn

    2-dimensional

    $Arr = @()
    $Arr += @()
    $Arr[n] += $Obj

    Im Sinne von Hashtables (Key/Value-Pairs) geht dies dann so:

    $Hash = @{} <= Man achte auf die Klammer
    $Hash["Key1"] = $Obj1
    $Name = "Key2"
    $Hash[$Name] = $Obj
    :
    :
    usw. usf.

    Dienstag, 10. Dezember 2019 16:33
  • Also wenn das XML ist, dann würde ich das jeweils in ein XML-Objekt stecken und diese dann in eine ArrayList packen. Und wenn Du in die ArrayList ne Hashtable packst, bei der eine der Properties dann als Wert das XML enthält -> voila...

    $AllFiles = Foreach ( $xmlfile in Get-Item *.xml ) {
        [PSCustomObject]@{
            Name = $xmlfile.Name
            Content = [xml]( Get-Content $xmlFile )
        }
    }
    Sinngemäß... Oder etwas anders dann mit der ArrayList oder xyz. Letzlich ist es ja Dein Code, Du mußt eine Variante finden, die Dir liegt.

    Greetings/Grüße, Martin - https://mvp.microsoft.com/en-us/PublicProfile/5000017 Mal ein gutes Buch über GPOs lesen? - http://www.amazon.de/Windows-Server-2012--8-Gruppenrichtlinien/dp/3866456956 Good or bad GPOs? My blog - http://evilgpo.blogspot.com And if IT bothers me? Coke bottle design refreshment - http://sdrv.ms/14t35cq

    Dienstag, 10. Dezember 2019 17:14
  • üblicherweise erstellen wir in Powershell keine leeren Arrays. Das ist normalerweise einfach nicht nötig. 

    Naja. Das Ergebnis von

    $a += "Erste Zeile"
    $a += "Zweite Zeile"
    $a += "Dritte Zeile"

    und

    $a = @()
    $a += "Erste Zeile"
    $a += "Zweite Zeile"
    $a += "Dritte Zeile"
    wird schon sehr unterschiedlich sein ;-)


    Evgenij Smirnov

    http://evgenij.smirnov.de

    Dienstag, 10. Dezember 2019 17:58
  • $Arr = @() <= Entspricht einer ArrayList

    nur sehr ungefähr, eigentlich eher nicht ;-)

    $Arr = @()
    $Arr += @()

    Das ergibt aber nicht etwa ein Array mit einem leeren Array als Mitglied #0 (also Kardinalität 1), sondern weiterhin einfach ein leeres Array (Kardinalität 0). Und selbst ein explizites @(@()) ergibt einfach bloß ein leeres Array...

    Man muss die Dinger schon komplett, im Zweifel mit nichtleeren Werten, initialisieren, wenn man ein pseudo-mehrdimensionales Array in PowerShell haben will.


    Evgenij Smirnov

    http://evgenij.smirnov.de



    Dienstag, 10. Dezember 2019 18:09
  • $Array += $Array2
    => entspricht leider nicht dem Hinzufügen des Objektes $Array2, sondern die Elemente aus $Array2 werden in $Array kopiert. Man erhält also tatsächlich nur weiterhin ein 1-dimensionales Array.
    In .Net entspricht dieses Verhalten der Funktion "AddRange(Array)".

    Hier übrigens ein interessanter Thread über die diversen Möglichkeiten Array, Mulitdimensions-Array und Hashtable.
    https://stackoverflow.com/questions/9397137/powershell-multidimensional-arrays

    Donnerstag, 12. Dezember 2019 09:18