2011-01-07 7 views
1

Schienen Ich versuche, diese zu sagenWie schreiben bedingte Anweisungen in einer einzigen Zeile?

self.preferred_amount * object.each{|li|li.variant}.collect{|li|li.weight} 

Das einzige Problem ist, dass bestimmte Gewichte gleich Null.

Sein, das der Fall ist, würde ich das hinzufügen, wenn sie gleich Null tun, machen sie gleich 0.

Gibt es eine Möglichkeit, diese Logik in der gleichen Zeile zu integrieren?

Oder gibt es eine Möglichkeit, diese Aussage noch mehr zu refaktorisieren als es ist?

+0

können Sie, was die "object.each" tut erklären? – tokland

+0

Es ist ein Fehler, einen Skalarbetrag mit einem Array zu multiplizieren. Willst du die Summe der Gewichte berechnen? –

+0

@wayne, ja, aber ich habe später hinzugefügt. Vielen Dank – Trip

Antwort

8

Ändern li.weight zu li.weight || 0

|| ist die "Kurzschluß oder" Operator. Wenn seine linke Seite truthy ist (weder falsch noch nil), kehrt sie zur linken Seite zurück, andernfalls kehrt sie zur rechten Seite zurück.

Es gibt eine Funktion in MRT> = 1.8.7, mit der Sie diese Anzeige machen können. Statt:

each{|li|li.variant} 

können Sie

each(&:variant) 

In Versionen von Ruby vor 1.8.7, erfordern die updates Juwel schreiben diese Funktion zu erhalten.

Besser als das, verschieben Sie die gesamte Logik in Objektklasse, z.

class Whatever 
    def variant_weights 
    each(&:variant).collect{ |li| li.weight || 0} 
    end 
end 

und es zu benutzen:

self.preferred_amount * object.variant_weights 

Beachten Sie jedoch, dass es ein Fehler ist eine skalare Menge von einem Array zu multiplizieren. Wenn Sie die Gewichte Summe bedeuten, dann:

class Whatever 
    def total_variant_weights 
    each(&:variant).collect{ |li| li.weight || 0}.inject(&:+) 
    end 
end 

und es zu benutzen:

self.preferred_amount * object.total_variant_weights 
2

nur || 0 das Gewicht:

self.preferred_amount * object.each{|li|li.variant}.collect{|li|li.weight || 0} 
5

Hinweis Alle Antworten sind korrekt für Ihren Zweck, aber um Ihre Frage direkt zu beantworten:

Wie schreibe ich eine bedingte Anweisung in einer einzigen Zeile? Schienen

Sie können ternäre Operatoren verwenden.Sie nehmen die folgende Form:

assertion ? value_if_true : value_if_false 
# if assertion is true, then value_if_true, otherwise, value_if_false 

zum Beispiel:

puts 4 < 5 ? 'you are on Earth' : 'you are on another planet' 
<%= @user.is_admin? ? 'you can access this page' : 'you aren\'t allowed to be here' %> 

Wie ich schon sagte, die oben genannten Antworten sind eigentlich das, was Sie sich für diese spezielle wollen (nicht, dass ein ternärer Operator wird nicht Arbeit in diesem Fall). Ich wollte Ihnen nur einen Einblick in One-Liners geben.

Beachten Sie auch, das ist nicht Ruby-spezifisch. Die meisten Programmiersprachen (einschließlich Ruby, PHP, CF, AS, JAVA, C, C# ...) haben ternäre Operatoren.

+0

gute Antwort, ich habe so etwas @models = Model.find (: all) .collect {| m | (Modellist [m.id]> 0)? m: false}, so wie ich gezwungen bin, einen alternativen Wert zu liefern (oder sonst bekomme ich einen Fehler), gibt es eine Möglichkeit, entweder einen Wert (links) oder nichts zu machen – jack

2

Die jeweils scheint redundant. Was ist mit:

self.preferred_amount * object.collect { |o| o.variant.weight.to_i } 

oder wenn Sie wirklich die Gewichte summieren gemeint:

self.preferred_amount * object.inject { |sum, o| sum + o.variant.weight.to_i }

Verwandte Themen