433 Stimmen

Wie man in Ruby Nullwerte zuordnet und entfernt

Tengo un map die entweder einen Wert ändert oder ihn auf null setzt. Ich möchte dann die Nulleinträge aus der Liste entfernen. Die Liste muss nicht beibehalten werden.

Dies ist mein derzeitiger Stand:

# 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, ich könnte einfach eine Schleife tun und bedingt in einem anderen Array wie dieses sammeln:

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 zu sein. Gibt es eine nette Art und Weise, eine Funktion über eine Liste abzubilden, Entfernen/Ausschließen der nils wie Sie gehen?

31voto

Fred Willmore Punkte 4096

Wenn Sie ein lockereres Kriterium für die Ablehnung wünschen, z.B. um leere Zeichenketten ebenso abzulehnen wie nil, könnten Sie dies verwenden:

[1, nil, 3, 0, ''].reject(&:blank?)
 => [1, 3, 0] 

Wenn Sie weiter gehen und Nullwerte zurückweisen wollen (oder eine komplexere Logik auf den Prozess anwenden wollen), können Sie einen Block zum Zurückweisen übergeben:

[1, nil, 3, 0, ''].reject do |value| value.blank? || value==0 end
 => [1, 3]

[1, nil, 3, 0, '', 1000].reject do |value| value.blank? || value==0 || value>10 end
 => [1, 3]

10voto

Abdullah Numan Punkte 129

Sie können verwenden #compact Methode auf das resultierende Array.

[10, nil, 30, 40, nil].compact => [10, 30, 40]

5voto

pnomolos Punkte 807

each_with_object ist wahrscheinlich der sauberste Weg, um dies zu tun:

new_items = items.each_with_object([]) do |x, memo|
    ret = process_x(x)
    memo << ret unless ret.nil?
end

Meiner Meinung nach, each_with_object ist besser als inject / reduce in bedingten Fällen, weil Sie sich nicht um den Rückgabewert des Blocks kümmern müssen.

0voto

Wand Maker Punkte 17998

Eine weitere Möglichkeit, dies zu erreichen, ist die unten dargestellte. Hier verwenden wir Enumerable#each_with_object um Werte zu sammeln, und nutzen Sie die Object#tap um eine temporäre Variable loszuwerden, die sonst für nil Prüfung des Ergebnisses der process_x Methode.

items.each_with_object([]) {|x, obj| (process x).tap {|r| obj << r unless r.nil?}}

Vollständiges Beispiel zur Veranschaulichung:

items = [1,2,3,4,5]
def process x
    rand(10) > 5 ? nil : x
end

items.each_with_object([]) {|x, obj| (process x).tap {|r| obj << r unless r.nil?}}

Alternativer Ansatz:

Wenn Sie sich die Methode ansehen, die Sie aufrufen process_x url Es ist nicht klar, was der Zweck der Eingabe ist. x in dieser Methode. Wenn ich davon ausgehe, dass Sie den Wert von x indem Sie ihm einige url und bestimmen, welche der x s wirklich in gültige Nicht-Null-Ergebnisse umgewandelt werden - dann kann es sein Enumerabble.group_by ist eine bessere Option als Enumerable#map .

h = items.group_by {|x| (process x).nil? ? "Bad" : "Good"}
#=> {"Bad"=>[1, 2], "Good"=>[3, 4, 5]}

h["Good"]
#=> [3,4,5]

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X