Wie können mehrere Arrays in Ruby effizient verkettet werden?

8

Ich wollte nur mehrere Arrays in Ruby verketten und konnte keinen zufriedenstellenden Weg finden.

Beispieleingabe:

%Vor%

Erwartetes Ergebnis: (ohne die vorhandenen Arrays zu ändern)

%Vor%

Meine tatsächlichen Arrays sind viel größer, also bin ich an einer effizienten Lösung interessiert. Es kann auch mehr als drei Arrays geben, daher wird eine kurze Syntax bevorzugt.

Was ich bisher versucht habe

  • foo + bar + baz ist das Offensichtliche, es ist prägnant und klar. Aber es wird als (foo + bar) + baz ausgewertet. Mit anderen Worten: Es wird ein intermediäres Array [1, 2, 3, 4, 5, 6] erstellt, das nach der gesamten Operation verworfen wird. Wie in der Dokumentation erwähnt:

      

    die wiederholte Verwendung von += auf Arrays kann ziemlich ineffizient sein

  • [*foo, *bar, *baz] enthält im Grunde die Elemente, was auch für große Arrays nicht sehr effizient ist. Es sieht auch eher wie ein Hack für mich aus.

  • [foo, bar, baz].flatten(1) scheint sogar noch schlechter zu sein als das oben genannte, was die Leistung angeht.

  • [].concat(foo).concat(bar).concat(baz) ist am schnellsten, aber es sieht umständlich aus und erfordert mehrere Methodenaufrufe.

Sollte es für solch eine grundlegende Aufgabe keine einfache Klassenmethode geben? Etwas wie:

%Vor%

Vermisse ich etwas Offensichtliches?

    
Stefan 09.11.2016, 15:30
quelle

3 Antworten

12

Wenn Sie bereits festgestellt haben, dass die Mehrfachverkettung die schnellste Methode ist, können Sie sie mit reduce:

schöner schreiben %Vor%     
Max 09.11.2016, 15:52
quelle
6

Ich habe einen anderen Benchmark erstellt, der + , concat und eine benutzerdefinierte C-Erweiterung mit einer variablen Anzahl von Arrays vergleicht.

Ergebnis

  • die C-Erweiterung war immer am schnellsten und ungefähr 2-3x schneller als concat
  • plus wird sehr langsam, wenn Sie viele Arrays
  • verketten

Fazit

Obwohl "2-3x" nach einer großen Verbesserung klingt, sind es in absoluten Zahlen nur wenige Millisekunden. Ich habe einen größeren Unterschied erwartet, da ich das Array nicht neu skalieren muss, aber das ist offensichtlich kein großer Faktor.

IMO, concat ist ein anständiger Darsteller und ich sehe keinen dringenden Bedarf für eine C-Erweiterung.

Meine Test-Arrays enthalten nil -Werte. Andere Elemente scheinen (relativ gesehen) keine unterschiedlichen Ergebnisse zu liefern.

Ich habe flat_map nicht eingeschlossen, weil dies gleichbedeutend mit concat ist.

%Vor%

plus wird von den folgenden Ergebnissen ausgeschlossen

%Vor%

Testcode:

%Vor%

C extension: (eigentlich ein Patch, ich habe das zu Rubys array.c hinzugefügt)

%Vor%

Sie müssen diese Methode in Init_Array über:

registrieren %Vor%     
Stefan 10.11.2016 13:05
quelle
2

Hat einige Benchmarks und einfache + ist am effizientesten. Daher würde ich vorschlagen, die Zwischenerstellung eines Arrays zu vernachlässigen.

Sie könnten so eine neue Methode concat_all zu Array hinzufügen, aber Sie müssten auch gemischte und mehrdimensionale Arrays berücksichtigen.

%Vor%

Hier meine Benchmarks

%Vor%

Und hier die Ergebnisse

%Vor%     
peter 09.11.2016 17:23
quelle

Tags und Links