Was ist der schnellste Weg, die Elemente in einer Liste von Zahlenlisten in Zeichen umzuwandeln? Diese Herausforderung ist eine Erweiterung der Frage, die hier in der Community gestellt wird. Ich habe beschlossen, acht Ansätze zu testen: drei iterative Methoden ( For , For Each und Transform Each ), vier nicht iterative Methoden (Tabellenoperationen, Ausdrücke, Wörter + Ausdrücke und Regex ) und eine Hybridmethode ( Words + Transform Each ). Fünf dieser Methoden, die weder Regex noch Ausdrücke beinhalten, wurden im verlinkten Beitrag berücksichtigt. Die Methoden, die Words und Regex verwenden, sind insofern ein kleiner Trick, als sie einen Nebeneffekt von String-Operationen ausnutzen – insbesondere kann jede Datenstruktur in eine Zeichenfolge umgewandelt und entsprechend analysiert werden. Ich überlasse es dem Leser, ob er diesen Ansatz für legitim hält. Ich kenne ein paar Leute, die das missbilligen würden!
Mithilfe eines raumfüllenden Designs habe ich vier Faktoren untersucht: Anzahl der Listen, Anzahl der Listenelemente, ob die Listen eine gleiche oder ungleiche Anzahl von Elementen hatten, und Zahlentyp: Ganzzahl oder Gleitkomma. Das Design befindet sich in der Liste der Listen – Experimentelle Läufe.JMP . Bruchwerte aus der ursprünglichen Designgenerierung wurden gerundet. Für jeden Lauf wurden zehn Wiederholungen durchgeführt. Der Code, den ich zum Ausführen des Experiments verwendet habe, befindet sich in „Liste der Listen ausführen experiment.JSL“ und die Ergebnisse in „Liste der Listen Ergebnisse.JMP“. Vorläufe mit Regex waren extrem langsam und wurden daher nicht in Betracht gezogen.
Um Methoden zu vergleichen, berechne ich die Rangfolge jeder Methode nach Lauf und Replikation sowie die Differenz zwischen der Laufzeit und der mittleren Laufzeit für alle Replikationen innerhalb eines experimentellen Laufs. Kleiner ist besser. Die folgenden Diagramme deuten darauf hin , dass Transform Each , Tabellenoperationen und die Words- Methoden überlegen waren. Während der tatsächliche Zeitunterschied gering ist (Werte werden in Mikrosekunden angegeben), werden diese Methoden durchweg höher eingestuft und weisen eine geringere Variabilität auf.


Um zu sehen, ob es Unterschiede zwischen den vier Methoden gibt, habe ich das Experiment mit größeren Listen ( List of Lists Big – Experimental Runs.JMP und List of Lists Big Results.JMP ) erneut durchgeführt. Betrachtet man die Zeitunterschiede zur mittleren Zeit innerhalb des Laufs, so zeigt sich, dass Transform Each und Tabellenoperationen mit zunehmender Gesamtzahl der Elemente die beste Leistung erbringen. Dies ist ein erfreuliches Ergebnis, da Transform Each gerade erst in JMP 16 eingeführt wurde und Tabellenoperationen eine gute Lösung für diejenigen darstellen, die noch mit JMP 15 arbeiten.

Für die zweite Herausforderung habe ich Sie gebeten, eine Liste von Listen umzusetzen. Eine transponierte Liste von Listen sammelt alle ersten Elemente aus den Eingabelisten in der ersten Ausgabeliste, alle zweiten Eingabeelemente in der zweiten Ausgabeliste usw. Wenn die Eingabe n Listen hätte, hätte jede Ausgabeliste n Elemente. Die Anzahl der Ausgabelisten würde dem Maximum der Anzahl der Elemente in jeder Liste entsprechen. Während die Anzahl der Eingabelisten leicht zu bestimmen ist, erfordert die Anzahl der Ausgabelisten das Zählen der Elemente in jeder Eingabeliste. Ist das notwendig? Führt es zu einem schnelleren Prozess?
Um diese Frage zu beantworten und bestimmte Methoden zu testen, habe ich einen weiteren raumfüllenden Entwurf durchgeführt. Darin habe ich mir drei iterative Methoden ( For , For Each und Transform Each ) angesehen, die jeweils zwei Ansätze verwenden: einer berechnet die Anzahl der Ausgabelisten vor dem Erstellen der Ausgabe, was ein zweimaliges Durchlaufen der Eingabe erfordert, und der andere erstellt die Ausgabe mithilfe von eine einzelne Schleife über die Eingabe. Darüber hinaus habe ich mir die Verwendung von Tabellenoperationen angesehen. Es wurden sechs verschiedene Listenelementtypen berücksichtigt (Ganzzahl, Gleitkommazahl, 1-Zeichen, 8-Zeichen, 15-Zeichen und Zeichen mit variabler Breite (maximale Länge 15) sowie feste und variable (innere) Listenlängen.
Während meiner ersten Codierung habe ich festgestellt, dass es schneller ist, die Ausgabeliste mit einer leeren Liste zu erstellen und „Einfügen in“ zu verwenden, als die Ausgabe mithilfe von „Wiederholen “ oder „Ausdrücken“ vorab mit fehlenden Werten zu füllen. Sie können den Code in Prebuild oder Insert.JSL verwenden, um dies selbst zu überprüfen. Eine zweite Entdeckung hatte mit Transform Each und For Each zu tun. Wenn Sie mit diesen Funktionen nicht vertraut sind, verhalten sie sich etwas anders als Ihre standardmäßige For- oder While -Schleife, da sie es Ihnen ermöglichen, über Listen, Matrizen oder assoziative Arrays zu iterieren, ohne deren Größe angeben zu müssen. Dadurch kann der Code etwas kompakter und sauberer werden. Die Struktur eines grundlegenden Aufrufs einer dieser Funktionen ist
fnName ({ indValue , ind }, Container , Body )
Dabei ist fnName „ For Each“ oder „Transform Each“ , indValue der Wert des Containers am Index ind , „container “ eine Matrix, Liste oder ein assoziatives Array und „ body “ der Hauptteil des Codes. Bei der Arbeit mit großen Behältern ist Vorsicht geboten. Die Verwendung großer Datenstrukturen als Container oder indValue verlangsamt die Ausführung erheblich. Ein Beispiel hierfür finden Sie in Using For Each und Transform Each.JSL . Darin zählen wir die Anzahl der Elemente in jeder Liste einer Liste von Listen. Die ersten beiden Codeblöcke entsprechen der Art und Weise, wie Sie das Problem möglicherweise codieren. Der erste verwendet jede Unterliste als Eingabewert, der zweite indiziert die Unterlisten. Vergleichen Sie dies mit dem dritten Block, in dem die Indizes für aList explizit erstellt und in der Schleife verwendet werden. Abhängig von der Größe von aList können die Verbesserungen der Verarbeitungsgeschwindigkeit das Hundertfache oder mehr betragen. Noch schneller ist Transform Each , sodass die resultierenden Werte zurückgegeben werden können. Die Blöcke 4 und 5 zeigen, dass die Ausgabedatenstruktur mit der für den Eingabecontainer verwendeten Datenstruktur übereinstimmt. Es gibt ein optionales Output()- Argument, um den Typ der Ausgabedatenstruktur zu steuern.
Der Code zum Testen der verschiedenen Transpositionsmethoden befindet sich in Transposelists.JSL . Wie oben wurde ein raumfüllendes Design verwendet, um die Ausgabe unter verschiedenen Bedingungen zu vergleichen. Im Gegensatz zum obigen Code wird für jede Wiederholung eine neue Datenstruktur erstellt. Die ersten drei Methoden lesen die Eingabe und erstellen die Ausgabe in einem einzigen Block. Die nächsten drei legen zunächst die Größe der Ausgabelisten fest, bevor die Eingabe verarbeitet wird. Die vorletzte Methode verwendete Tabellenoperationen und die letzte Transform Each-Methode war so strukturiert, dass ihre Ausgabewerte verwendet wurden.

Es erwies sich als schneller, die Größe der Ausgabelisten vorab festzulegen, als dies in einem einzelnen Block zu versuchen. Die verschiedenen Implementierungen von Transform Each zeigen die Geschwindigkeitsverbesserungen, die durch die Arbeit mit seinen Ausgabewerten erzielt werden. Die Ergebnisse befinden sich in Transpose results.JMP . Ein Experiment mit größeren Listen zum Vergleich von For Each , Transform Each ( 2. Implementierung) und Tabellenoperationen finden Sie in Transpose results big.JMP . Die Ergebnisse legen nahe, dass Tabellenoperationen im Allgemeinen die beiden anderen Ansätze übertreffen.

Um zusammenzufassen, was wir entdeckt haben:
- Zeitlich: Transformiere Each < For Each < For
- Tabellenoperationen können superschnell sein, wenn keine Spaltenformeln beteiligt sind. In früheren Beiträgen haben wir gesehen, dass Spaltenformeln abhängig von ihrer Komplexität Vorgänge bis zu einem Punkt verlangsamen können, an dem Iterationen oder Ausdrücke günstiger sind.
Ich habe für diese Herausforderung nicht das typische Feedback erhalten, das ich in der Vergangenheit hatte, daher bin ich mir sicher, dass es einen besseren Ansatz gibt. Ich würde gerne Ihre Kommentare hören. Suchen Sie nächsten Monat nach einer neuen Herausforderung.