none
Großes Array verändern RRS feed

  • Frage

  • Hallo,

    ich habe aus eine Datei (MAB-Datei, hat was mit Büchern zu tun) ein ca. 2 Mio Felder großes Array gemacht das ich bearbeiten muss. Die Aufgabe ist es, an bestimmten Stellen eine neue Zeile (MAB-Feld) einzufügen. Bisher mach ich das so, dass ich das Array an der Stelle Aufteile und dann mit der neuen Zeile zusammenfüge.

    In etwa so:

    #$i ist die Position wo die neue Zeil hin soll.

    $MAB_TOP= $NEW_MAB[0..($i-1)]
    $MAB_BOTTOM= $NEW_MAB[$i..$MAB_ALL] # MAB_ALL ist die Größe des Array und wird immer neu berechnet.
    $MAB_INPUT = '035  DIESEN DATENSATZ NICHT EINSPIELEN'
    $NEW_MAB = $MAB_TOP+$MAB_INPUT+$MAB_BOTTOM

    Das klappt auch, da ich aber etwa 20000 Ersetzungen machen muss, zieht sich das seeeehr lange hin. 

    Kennt irgendjemand einen Weg ein Array besser und effizienter zu bearbeiten?

    $MAB.inject ($I,$MAB_INPUT) wäre nicht schlecht :-) gibts leider nicht.

    Torsten



    • Bearbeitet Sulucum Donnerstag, 19. August 2021 09:03
    Donnerstag, 19. August 2021 08:59

Antworten

  • Moin,

    Nachtrag: was Du natürlich auch machen kannst, ist statt Array eine ArrayList verwenden und die Datensätze dazwischen mit der Methode .Insert(Index,Element) einfügen.

    Wie die Performance wird, musst Du testen, aber in jedem Fall besser als jetzt.


    Evgenij Smirnov

    http://evgenij.smirnov.de

    • Als Antwort markiert Sulucum Mittwoch, 5. Januar 2022 12:47
    Donnerstag, 19. August 2021 15:25
  • Moin,

    zwei Anmerkungen zur Orga:

    1. Code bitte als Code posten (2. Button von rechts)
    2. groß geschriebene Namen sind in PowerShell zwar syntaktisch zulässig, aber extrem unüblich

    In der Sache:

    PowerShell-Arrays sind so ziemlich das langsamste und unhandlichste Konstrukt, das man in PowerShell verwenden kann. Hier ein alter Beitrag von mir, um einen Überblick zu bekommen: https://it-pro-berlin.de/2017/08/powershell-wie-schnell-sind-arrays/

    Ich würde das auf eine der folgenden Arten lösen:

    1. Eine Hashtable mit Ordnungsparameter als Name (muss ausreichend große "Löcher" beinhalten, also vielleicht mit 00000010000000, 00000020000000, 00000030000000 usw. starten), die einzufügenden Werte an die Hashtable anfügen, aber im Namen für die richtige Ordnung sorgen (00000011000000 wäre zwischen 00000010000000 und 00000020000000), am Ende mit einem Enumerator sortieren und ausgeben.
    2. (wäre vermutlich mein Favorit) das Gleiche mit einer SQL-Engine abwickeln - entweder SQL-Server oder halt SQLite. Das hätte den charmanten Vorteil, dass das Ganze nicht im RAM abläuft, sondern dauerhaft bestehen bleibt. Wenn man im RAM rechnen möchte, kann SQLite auch eine In-Memory-Datenbank erzeugen. Dazu habe ich mal einen Vortrag bei uns auf der User Group gehalten: https://it-pro-berlin.de/2021/03/folien-und-sample-code-zu-meinem-vortrag-bei-der-psug-berlin/

    Evgenij Smirnov

    http://evgenij.smirnov.de

    Donnerstag, 19. August 2021 09:28

Alle Antworten

  • Moin,

    zwei Anmerkungen zur Orga:

    1. Code bitte als Code posten (2. Button von rechts)
    2. groß geschriebene Namen sind in PowerShell zwar syntaktisch zulässig, aber extrem unüblich

    In der Sache:

    PowerShell-Arrays sind so ziemlich das langsamste und unhandlichste Konstrukt, das man in PowerShell verwenden kann. Hier ein alter Beitrag von mir, um einen Überblick zu bekommen: https://it-pro-berlin.de/2017/08/powershell-wie-schnell-sind-arrays/

    Ich würde das auf eine der folgenden Arten lösen:

    1. Eine Hashtable mit Ordnungsparameter als Name (muss ausreichend große "Löcher" beinhalten, also vielleicht mit 00000010000000, 00000020000000, 00000030000000 usw. starten), die einzufügenden Werte an die Hashtable anfügen, aber im Namen für die richtige Ordnung sorgen (00000011000000 wäre zwischen 00000010000000 und 00000020000000), am Ende mit einem Enumerator sortieren und ausgeben.
    2. (wäre vermutlich mein Favorit) das Gleiche mit einer SQL-Engine abwickeln - entweder SQL-Server oder halt SQLite. Das hätte den charmanten Vorteil, dass das Ganze nicht im RAM abläuft, sondern dauerhaft bestehen bleibt. Wenn man im RAM rechnen möchte, kann SQLite auch eine In-Memory-Datenbank erzeugen. Dazu habe ich mal einen Vortrag bei uns auf der User Group gehalten: https://it-pro-berlin.de/2021/03/folien-und-sample-code-zu-meinem-vortrag-bei-der-psug-berlin/

    Evgenij Smirnov

    http://evgenij.smirnov.de

    Donnerstag, 19. August 2021 09:28
  • Du könntest ein Dictionary @{} verwenden und die Zeilen in 100er Schritten durchnummerieren.
    Dann fügst du deine Zeilen ein (101, 501, ...).

    Bei der Ausgabe sortierst du nach Key.

    Donnerstag, 19. August 2021 09:30
  • Moin,

    Nachtrag: was Du natürlich auch machen kannst, ist statt Array eine ArrayList verwenden und die Datensätze dazwischen mit der Methode .Insert(Index,Element) einfügen.

    Wie die Performance wird, musst Du testen, aber in jedem Fall besser als jetzt.


    Evgenij Smirnov

    http://evgenij.smirnov.de

    • Als Antwort markiert Sulucum Mittwoch, 5. Januar 2022 12:47
    Donnerstag, 19. August 2021 15:25
  • Hallo,

    hat leider etwas gedauert.

    Ich habe das mit dem ArrayList versucht und bin zufrieden.

    Anstelle von 57 Stunden brauchte das Skript "nur noch" 11 Stunden. Das ist zwar immer noch viel, aber man kann es nun am Feierabend starten und am nächsten Tag ist die Sache erledigt.

    Am Ende wurde eine Datei mit 26.599.720 Zeilen geschrieben.

    Also vielen Dank für die Tipps.

    Torsten


    Mittwoch, 5. Januar 2022 12:47
  • Die Frage ist ja, wie du den Insert feststellst.
    Der einfachere Weg ist während des Verarbeiten des Arrays die Werte in ein anderes Array zu kopieren. Wenn dann neue Werte dazukommen brauchst du keinen Insert mehr sondern fügst an diese Stelle im Zielarray den Wert ein.

    Statt eines Array kann man auch mit einem TextStream arbeiten und während des Lesens auch gleich schreiben.
    Wenn man dann fertig ist, alte Datei löschen und neue Datei umbenennen.

    11 Stunden für 26,5 Mio Zeilen währen mir zu lange.

    https://stackoverflow.com/questions/4192072/how-to-process-a-file-in-powershell-line-by-line-as-a-stream

    Mittwoch, 5. Januar 2022 13:58