Um das Äquivalent zum Verständnis der Python-Liste zu erreichen, gehe ich wie folgt vor:
some_array.select{|x| x % 2 == 0 }.collect{|x| x * 3}
Gibt es einen besseren Weg, dies zu tun ... vielleicht mit einem Methodenaufruf?
ruby
list-comprehension
Schreibgeschützt
quelle
quelle
Antworten:
Wenn Sie wirklich möchten, können Sie eine Array # -Verständnismethode wie folgt erstellen:
Drucke:
Ich würde es wahrscheinlich genauso machen, wie du es getan hast.
quelle
[nil, nil, nil].comprehend {|x| x }
welche zurückgibt[]
.compact!
gibt alexey nil anstelle des Arrays zurück, wenn keine Elemente geändert werden. Ich denke also nicht, dass dies funktioniert.Wie wäre es mit:
Etwas sauberer, zumindest nach meinem Geschmack, und laut einem schnellen Benchmark-Test etwa 15% schneller als Ihre Version ...
quelle
some_array.map{|x| x * 3 unless x % 2}.compact
, was wohl besser lesbar / rubinartig ist.unless x%2
hat keine Auswirkung, da 0 in Ruby wahr ist. Siehe: gist.github.com/jfarmer/2647362Ich habe einen schnellen Benchmark erstellt, bei dem die drei Alternativen mit Map-Compact verglichen wurden scheint wirklich die beste Option zu sein.
Leistungstest (Rails)
Ergebnisse
quelle
reduce
in diesem Benchmark zu sehen (siehe stackoverflow.com/a/17703276 ).inject
==reduce
In diesem Thread scheint es unter Ruby-Programmierern einige Verwirrung darüber zu geben, was Listenverständnis ist. Jede einzelne Antwort setzt voraus, dass ein bereits vorhandenes Array transformiert wird. Die Stärke des Listenverständnisses liegt jedoch in einem Array, das im laufenden Betrieb mit der folgenden Syntax erstellt wird:
Das Folgende wäre ein Analogon in Ruby (die einzig angemessene Antwort in diesem Thread, AFAIC):
Im obigen Fall erstelle ich ein Array von zufälligen Ganzzahlen, aber der Block kann alles enthalten. Dies wäre jedoch ein Verständnis der Ruby-Liste.
quelle
Ich habe dieses Thema mit Rein Henrichs besprochen, der mir sagt, dass die Lösung mit der besten Leistung ist
Dies ist sinnvoll, da das Erstellen von Zwischen-Arrays wie bei der unveränderlichen Verwendung von
Enumerable#inject
vermieden wird und das Array nicht vergrößert wird, was zu einer Zuweisung führt. Es ist so allgemein wie alle anderen, es sei denn, Ihre Sammlung kann keine Elemente enthalten.Ich habe das nicht mit verglichen
Es ist möglich, dass Rubys C-Implementierung
Enumerable#select
auch sehr gut ist.quelle
Eine alternative Lösung, die in jeder Implementierung funktioniert und in O (n) anstelle von O (2n) ausgeführt wird, ist:
quelle
2
Dingen
mal statt ,1
wasn
mal und dann noch1
etwasn
mal :) Ein wichtiger Vorteil voninject
/reduce
ist , dass es keine bewahrtnil
Werte in der Eingangssequenz , die mehr list-comprehensionly VerhaltenIch habe gerade das Comprehens-Juwel in RubyGems veröffentlicht, mit dem Sie Folgendes tun können:
Es ist in C geschrieben; Das Array wird nur einmal durchlaufen.
quelle
Enumerable verfügt über eine
grep
Methode, deren erstes Argument ein Prädikat proc sein kann und deren optionales zweites Argument eine Zuordnungsfunktion ist. so funktioniert folgendes:Dies ist nicht so lesbar wie einige andere Vorschläge (ich mag Anoiaques einfaches
select.map
oder histokratisches Juwel), aber seine Stärken sind, dass es bereits Teil der Standardbibliothek ist, in einem Durchgang und ohne temporäre Zwischenarrays und erfordert keinen Wert außerhalb der Grenzen, wienil
er in dencompact
Vorschlägen zur Verwendung verwendet wird.quelle
Dies ist prägnanter:
quelle
[1,2,3,4,5,6].select(&:even?).map(&3.method(:*))
Das ist für mich in Ordnung. Es ist auch sauber. Ja, es ist das gleiche wie
map
, aber ich denke,collect
macht den Code verständlicher.sieht eigentlich besser aus, nachdem ich es unten gesehen habe.
quelle
Wie Pedro bereits erwähnt hat, können Sie die verketteten Anrufe mit
Enumerable#select
und zusammenführenEnumerable#map
, um ein Durchlaufen der ausgewählten Elemente zu vermeiden. Dies ist wahr, weilEnumerable#select
eine Spezialisierung von Falte oderinject
. Ich habe eine hastige Einführung gepostet in das Thema im Ruby-Subreddit veröffentlicht.Das manuelle Zusammenführen von Array-Transformationen kann mühsam sein. Vielleicht könnte jemand mit der
comprehend
Implementierung von Robert Gamble spielen , um diesesselect
/map
Muster schöner zu machen .quelle
Etwas wie das:
Nennen:
Welches kehrt zurück:
quelle
lazy
auf Array zu definieren und dann:(1..6).lazy{|x|x*3 if x.even?}
Eine andere Lösung, aber vielleicht nicht die beste
oder
quelle
Dies ist eine Möglichkeit, dies zu erreichen:
Im Grunde genommen konvertieren wir einen String in die richtige Ruby-Syntax für die Schleife. Dann können wir die Python-Syntax in einem String verwenden, um Folgendes zu tun:
oder wenn Ihnen das Aussehen der Zeichenfolge nicht gefällt oder Sie kein Lambda verwenden müssen, können Sie auf den Versuch verzichten, die Python-Syntax zu spiegeln und so etwas zu tun:
quelle
Ruby 2.7 wurde eingeführt,
filter_map
das so ziemlich das erreicht, was Sie wollen (Karte + Kompakt):Sie können mehr darüber lesen Sie hier .
quelle
https://rubygems.org/gems/ruby_list_comprehension
Schamloser Plug für mein Ruby List Comprehension-Juwel, um idiomatisches Ruby List-Verständnis zu ermöglichen
quelle
Ich denke, das Listenverständnis wäre das Folgende:
Da Ruby es uns ermöglicht, die Bedingung nach dem Ausdruck zu platzieren, erhalten wir eine Syntax ähnlich der Python-Version des Listenverständnisses. Da die
select
Methode nichts enthält, was gleichbedeutend istfalse
, werden alle Nullwerte aus der resultierenden Liste entfernt, und es ist kein Aufruf von compact erforderlich, wie dies der Fall wäre, wenn wirmap
odercollect
stattdessen verwendet hätten.quelle