Ich habe eine, map
die entweder einen Wert ändert oder auf Null setzt. Ich möchte dann die Null-Einträge aus der Liste entfernen. Die Liste muss nicht aufbewahrt werden.
Folgendes habe ich derzeit:
# A simple example function, which returns a value or nil
def transform(n)
rand > 0.5 ? n * 10 : nil }
end
items.map! { |x| transform(x) } # [1, 2, 3, 4, 5] => [10, nil, 30, 40, nil]
items.reject! { |x| x.nil? } # [10, nil, 30, 40, nil] => [10, 30, 40]
Ich bin mir bewusst, dass ich einfach eine Schleife machen und bedingt in einem anderen Array wie diesem sammeln könnte:
new_items = []
items.each do |x|
x = transform(x)
new_items.append(x) unless x.nil?
end
items = new_items
Aber es scheint nicht so idiomatisch. Gibt es eine gute Möglichkeit, eine Funktion einer Liste zuzuordnen und dabei die Nullen zu entfernen / auszuschließen?
filter_map
, was dafür perfekt zu sein scheint. Spart die Notwendigkeit, das Array erneut zu verarbeiten, anstatt es beim ersten Mal wie gewünscht durchzuziehen. Mehr Infos hier.Antworten:
Ruby 2.7+
Da ist jetzt!
Ruby 2.7 wird
filter_map
genau für diesen Zweck eingeführt. Es ist idiomatisch und performant, und ich würde erwarten, dass es sehr bald zur Norm wird.Zum Beispiel:
In Ihrem Fall, wenn der Block zu Falsey ausgewertet wird, einfach:
" Ruby 2.7 fügt Enumerable # filter_map hinzu " ist eine gute Lektüre zu diesem Thema, mit einigen Leistungsbenchmarks gegen einige der früheren Ansätze für dieses Problem:
quelle
Sie könnten verwenden
compact
:Ich möchte die Leute daran erinnern, dass wenn Sie ein Array erhalten, das nils als Ausgabe von a enthält
map
Blocks erhalten und dieser Block versucht, Werte bedingt zurückzugeben, Sie nach Code riechen und Ihre Logik überdenken müssen.Zum Beispiel, wenn Sie etwas tun, das dies tut:
Dann nicht. Stattdessen vor dem
map
,reject
was Sie nicht wollen oderselect
was Sie wollen:Ich denke darüber
compact
nach, ein Chaos als letzten Versuch zu beseitigen, um Dinge loszuwerden, mit denen wir nicht richtig umgegangen sind, normalerweise weil wir nicht wussten, was auf uns zukommt. Wir sollten immer wissen, welche Art von Daten in unserem Programm herumgeworfen werden. Unerwartete / unbekannte Daten sind schlecht. Jedes Mal, wenn ich Nullen in einem Array sehe, an dem ich arbeite, untersuche ich, warum sie existieren, und prüfe, ob ich den Code verbessern kann, der das Array generiert, anstatt Ruby Zeit und Speicher zu verschwenden, um Nullen zu generieren, und dann das Array zu durchsuchen, um sie zu entfernen sie später.quelle
nil
Einträge entfernen, keine leeren Zeichenfolgen. Übrigens,nil
ist nicht dasselbe wie eine leere Zeichenfolge.reduce
oderinject
?compact
ist am schnellsten, aber wenn Sie den Code am Anfang richtig schreiben, müssen Sie sich nicht mehr vollständig mit nils befassen.Versuchen Sie es mit
reduce
oderinject
.Ich bin mit der Antwort akzeptiert , dass wir nicht
map
undcompact
, aber nicht aus den gleichen Gründen.Ich fühle mich tief in mir, das ist
map
danncompact
gleichbedeutend mitselect
dannmap
. Bedenken Sie:map
ist eine Eins-zu-Eins-Funktion. Wenn Sie eine Zuordnung von einem Wertesatz und von Ihnenmap
vornehmen, möchten Sie einen Wert im Ausgabesatz für jeden Wert im Eingabesatz. Wenn Sie vorher müssenselect
, dann wollen Sie wahrscheinlich keinemap
am Set. Wenn Sieselect
danach (odercompact
) müssen, dann möchten Sie wahrscheinlich keinemap
am Set. In beiden Fällen iterieren Sie zweimal über den gesamten Satz, wenn einreduce
nur einmal ausgeführt werden muss.Außerdem versuchen Sie auf Englisch, "eine Menge von ganzen Zahlen in eine Menge von geraden ganzen Zahlen zu reduzieren".
quelle
In Ihrem Beispiel:
Es sieht nicht so aus, als hätten sich die Werte geändert, außer dass sie durch ersetzt wurden
nil
. Wenn dies der Fall ist, dann:wird genügen.
quelle
Wenn Sie ein lockereres Ablehnungskriterium wünschen, um beispielsweise leere Zeichenfolgen sowie Null abzulehnen, können Sie Folgendes verwenden:
Wenn Sie weiter gehen und Nullwerte ablehnen möchten (oder eine komplexere Logik auf den Prozess anwenden möchten), können Sie einen Block zum Ablehnen übergeben:
quelle
blank?
es nur in Schienen erhältlich ist, könnten wir verwenden,items.reject!(&:nil?) # [1, nil, 3, nil, nil] => [1, 3]
die nicht an Schienen gekoppelt sind. (würde aber leere Zeichenfolgen oder Nullen nicht ausschließen)Auf jeden Fall
compact
ist der beste Ansatz zur Lösung dieser Aufgabe. Wir können jedoch das gleiche Ergebnis nur mit einer einfachen Subtraktion erzielen:quelle
each_with_object
ist wahrscheinlich der sauberste Weg hierher:Meiner Meinung nach
each_with_object
ist es besser alsinject
/reduce
in bedingten Fällen, weil Sie sich nicht um den Rückgabewert des Blocks kümmern müssen.quelle
Eine weitere Möglichkeit, dies zu erreichen, ist die unten gezeigte. Hier verwenden wir
Enumerable#each_with_object
, um Werte zu sammeln und umObject#tap
temporäre Variablen zu entfernen, die ansonsten für dienil
Überprüfung des Ergebnisses derprocess_x
Methode benötigt werden.Vollständiges Beispiel zur Veranschaulichung:
Alternativer Ansatz:
Wenn Sie sich die Methode ansehen
process_x url
, die Sie aufrufen , ist nicht klar, welchen Zweck die Eingabex
in diese Methode hat. Wenn ich davon ausgehe, dass Sie den Wertx
von verarbeiten, indem Sie einige übergebenurl
und feststellen, welche derx
s wirklich zu gültigen Nicht-Null-Ergebnissen verarbeitet werden, ist dies möglicherweiseEnumerabble.group_by
eine bessere Option alsEnumerable#map
.quelle