2016-09-30 2 views
2

Wie können Sie ein Array in Ruby, die nur eine Variable verwendet, wenn es existiert, und sonst nil an ihrer Stelle verwendet. Mit der bedingten Logik innerhalb des Array-Konstruktors.Konstruieren Sie ein Ruby-Array mit bedingter Logik innerhalb

Vereinfachtes Beispiel:

a = 1 
c = 3 

arr = [a, b || nil, c] 

Ich habe eine Reihe unterschiedlicher Art und Weise versucht, aber sie arbeiten nicht so fühle ich mich wie grundlegende hier etwas fehlt bin.

  1. (b || nil)
  2. b ? b : nil
  3. b.nil? ? nil : b

Ist das möglich?

Kontext: Dieser Array-Konstruktor wird innerhalb einer Schleife verwendet, die von mehreren verschiedenen Modellen verwendet wird. Einige Modelle haben das b Attribut und andere nicht, was es schwierig macht, die Logik außerhalb zu extrapolieren.

+1

Warum würden 'b' nicht existieren? Das ist wirklich eine ungewöhnliche Sache in Ruby-Code zu sehen. – tadman

+0

Sie sagen beide "verwendet eine Variable, wenn es existiert" und "Einige Modelle haben das Attribut" b "und einige nicht". Die erste besagt, dass "b" eine Variable ist, die zweite besagt, dass "b" ein Methodenaufruf ist, was ist das? –

+0

Das reale Beispiel ähnelt eher @ @ instance.attribute_b. Die Methode mit dieser Logik iteriert Abfrageergebnisse für mehrere verschiedene Modelle (separat); Einige der Modelle haben kein 'attribute_b'. –

Antwort

2

Da Ihr b tatsächlich ein Modellattribut ist, das von der aktuellen self unterstützt wird oder nicht, ist b überhaupt keine Variable. b ist ein Methodenaufruf, und Sie sind nicht daran interessiert, ob die "Variable "Existiert, Sie sind daran interessiert, ob self auf b reagiert. Daher möchten Sie respond_to? verwenden:

arr = [a, respond_to?(:b) ? b : nil, c] 

oder vielleicht:

arr = [a, respond_to?(:b, true) ? b : nil, c] 

wenn Sie b sein, um einen nicht-öffentlichen Verfahren zulassen möchten.

defined?(b) sollte auch in diesem Fall funktionieren (es sei denn b 's Accessor-Methode wird automatisch über method_missing erstellt), aber es wird ziemlich rätselhaft für jeden, der Ihren Code betrachten. Die Verwendung von respond_to?, um zu sehen, ob ein Objekt eine Methode/ein Attribut hat, wäre idiomatischer.

respond_to? verwenden, wenn sie mit method_missing natürlich konfrontiert wird davon ausgegangen, dass sowohl method_missing und respond_to? außer Kraft gesetzt wurden, aber das sollte eine relativ sichere Annahme.

0

Dies wird den Trick:

arr = [a, b = b || nil, c] 

Beispiel 1:

a = 1 
c = 3 

arr = [a, b = b || nil, c] 
p arr #=> [1, nil, 3] 

Beispiel 2:

a = 1 
b = 2 
c = 3 

arr = [a, b = b || nil, c] 
p arr #=> [1, 2, 3] 
+1

kann auf 'arr = [a, b || = nil, c] ' – Doon

+0

@Doon gekürzt werden ja guter Punkt, vermisse ich diese Dinge beim Versuch, eine schnelle Antwort zu posten. Ich werde jedoch Ihre Empfehlung nicht aufnehmen, da dies bereits eine andere Antwort hat, aber danke. –

+1

@ sagarpandya82 - gehen Sie voran und aktualisieren Sie es. Du wirst mich nicht beleidigen. :) – CDub

3

Ja, können Sie defined? Methode verwenden. Es gibt "local-variable" zurück, wenn die Variable existiert, andernfalls wird nil zurückgegeben.

arr = [a, defined?(b) ? b : nil, c] 
+0

'arr = [a, definiert? (B)? b: nil, c] 'ist ein bisschen sauberer – Tilo

+0

@Tilo Du hast recht, es sieht besser aus. –

+0

Dies ist die richtige Antwort, da "b" nicht garantiert definiert ist. – CDub

0

können Sie tun:

arr = [a, (b ||= nil), c]

Beispiel:

a = 1 
b = nil 
c = 3 

> arr = [a, (b ||= 33), c] 
=> [1, 33, 3] 

b = 2 

> arr = [a, (b ||= 33), c] 
=> [1, 2, 3] 

Wenn b nicht definiert werden kann, müssen Sie defined? verwenden:

> arr = [a, (defined?(b) ? b : nil), c] 
=> [1, nil, 3] 
+0

Es ist nicht notwendig, den Ausdruck in Klammern zu schließen, die Kommas sind ausreichend, aber aus Gründen der Lesbarkeit würde ich jedes Element in das Array in einer separaten Zeile setzen, damit man leicht sehen kann, was passiert. –

+0

Während nicht notwendig, in einer einzigen Zeile, ist es viel einfacher zu lesen und zu bestimmen, Logik im Vergleich zu einer Variablen ... – CDub

+0

Ja, aber es ist fraglich, ob es überhaupt eine einzige Zeile sein sollte. Wenn Sie es in mehrere Zeilen aufteilen, ergibt sich dasselbe, die Geschwindigkeit wird nicht verringert, aber die Lesbarkeit wird verbessert. –

0

Ugh. Schreib keinen Code wie diesen. Stattdessen brechen sie in verständlicher Stücke:

a = 1 
c = 3 

b ||= nil 

arr = [a, b, c] 

Oder verwenden vertikalen Raum das Gehirn zu helfen, zu sehen, was los ist:

arr = [ 
    a, 
    b ||= 3, 
    c 
] 
Verwandte Themen