2016-12-31 5 views
0

Abflachen verstehe ich eine harte Zeit, warum dieses Stück Code funktioniert:ein Array rekursiv in Ruby

def flatten(array, result = []) 
    array.each do |element| 
    if element.is_a? Array 
     flatten(element, result) 
    else 
     result << element 
    end 
    end 
    result 
end 

Insbesondere, warum es ohne das Ergebnis des Flatten Methodenaufrufes zuweisen, die funktioniert der Ergebnis-Array, etwa so:

def flatten1(array, result = []) 
    array.each do |element| 
    if element.is_a? Array 
     result = flatten(element, result) 
    else 
     result << element 
    end 
    end 
    result 
end 

Beide produzieren den gleichen Ausgang:

p flatten [1,2,[3,4,[5,[6]]]] # [1, 2, 3, 4, 5, 6] 
p flatten1 [1,2,[3,4,[5,[6]]]] # [1, 2, 3, 4, 5, 6] 
+0

[Hier ist eine längere Diskussion] (http:

Eine idiomatische Ruby-Version wie folgt aussehen würde // stackoverflow.com/questions/1872110/is-ruby-pass-by-reference-or-by-value#10974116) und es gibt wahrscheinlich mehrere weitere auf der Website, aber kurze Antwort ist, dass die "Array-Ergebnis" an die Funktion übergeben Übergibt das tatsächliche Objekt, nicht eine Kopie davon, und das Objekt wird durch 'result << element' innerhalb der Funktionen modifiziert on, also wenn es rekursiv übergeben wird, wird es kontinuierlich ohne Neuzuweisung geändert –

Antwort

0

The flatten Methode ändert zerstörend sein zweites Argument result in Zeile 6 und übergibt das modifizierte Array als Argument an den rekursiven Aufruf in Zeile 4. Es besteht keine Notwendigkeit, etwas von der Methode zurückzugeben, da das Array, das Sie als zweites Element übergeben, destruktiv geändert wird die abgeflachte Version des Eingangs-Array haben hängten:

my_array = [:foo] 

flatten([1, [2, [3, [4]]]], my_array) 

my_array 
#=> [:foo, 1, 2, 3, 4] 

es ist allgemein schlechte Form betrachtet Objekte als Argumente übergeben zu ändern oder Werte zurückzugeben, indem Eingabeargumente statt zu modifizieren, wissen Sie, es einfach zurück. Es sieht so aus, als ob der Code von einem C-Programmierer geschrieben wurde, der das zweite Argument als Ausgabepuffer verwenden wollte.

def flatten(ary) 
    ary.each_with_object([]) do |el, res| 
    if el.is_a?(Array) 
     res.concat(flatten(el)) 
    else 
     res << el 
    end 
    end 
end 

oder eine rein funktionale Version ohne Mutation überhaupt:

def flatten(ary) 
    ary.inject([]) do |res, el| 
    res + if el.is_a?(Array) 
     flatten(el) 
    else 
     [el] 
    end 
    end 
end