2012-04-14 3 views
3

Zunächst werde ich so etwas wie unten tun:Rubin: Enumerator Ketten

arr = [[1,2],[3,4]] 
new_arr = 
arr.map do |sub_arr| 
    sub_arr.map do |x| 
     x+1 
    end 
end 

p new_arr 

Ausgang:

[[2,3],[4,5]] 

Aber dann habe ich versucht, kurz, um es von "Verkettungs up" den Aufzählungen:

arr.map.map{|x| x+1} 

Dann gibt es Fehler to_ary method missing

I debuggt durch

arr.each.each{|x| p x} 

Output:

[1,2] 
[3,4] 

, die die ursprüngliche Matrix ist und nur einmal desected.

Wie kann ich zwei Karten/jede Aufzählung verketten, so dass es Aufzählung in 2 (oder mehr) Ebenen? Oder muss es in dem Block sein?


Update:

Nach einiger Suche, anscheinend eine Kette obj.Enumerator.Enumerator.Enumerator... aufzählt nur obj die einmal, und nur 1 Stufe Tiefe. Um tiefer zu gehen, ist eine Blockierung erforderlich. Ich arbeitete einfachen Code aus, der String in Block umwandelte (Proc/Lambda; ähnlich wie das zu blockierende, aber mehr Gebrauch; mehr wie eine funktionale Syntax), so dass Block vermieden wird. Jemand hat ähnlichen Code String#to_proc, aber ich konnte es nicht finden, und die x,y Sache darin appelliert nicht zu meinem Geschmack. Ich benutze $0,$1,$2,...

Beispielcode (das vorherige Beispiel wird wie geschrieben):

arr = [[1,2],[3,4]] 
new_arr = arr.map(&'[$0+1,$1+1]') 
p new_arr 

Ich werde den ursprünglichen Code schieben später GitHub. Sie können Chat verwenden, um mich zu kontaktieren, wenn Sie es vorher sehen möchten, weil ich wirklich zögern :)

Antwort

2

Vielleicht brauchen Sie ein map, die Sie nur auf die Blätter bewerben möchten:

module Enumerable 
    def nested_map &block 
    map{|e| 
     case e 
     when Enumerable 
     e.nested_map(&block) 
     else 
     block.call(e) 
     end 
    } 
    end 
end 

p [[1,2], [3,4]].nested_map(&:succ) 
#=> [[2, 3], [4, 5]] 

oder eine map die gelten würde nur auf n -te Ebene der verschachtelten Struktur.

module Enumerable 
    def deep_map level, &block 
    if level == 0 
     map(&block) 
    else 
     map{|e| e.deep_map(level - 1, &block)} 
    end 
    end 
end 

p [[1,2], [3,4]].deep_map(1, &:succ) 
#=> [[2, 3], [4, 5]] 
0

Um dies zu tun, indem Sie x+1 nur einmal schreiben, müssen Sie es in einen Block setzen. Andernfalls können Sie Folgendes tun:

new_arr = arr.map {| x, y | [X + 1, y + 1]}

Oder, wenn Sie darauf bestehen, können Sie tun:

new_arr = arr.flatten (1) .map {| x | x + 1} .each_slice (2).to_a

2

wie ein Job für Rekursion Sounds:

def zipper(args) 
    args[0].respond_to?(:each) ? args.map{|a| zipper(a)} : args.map{|i| i+1} 
end 

zipper([[1,2],[3,4]]) 
# => [[2, 3], [4, 5]] 

zipper([[[1,2],[3,4]],[5,6]]) 
# => [[[2, 3], [4, 5]], [6, 7]] 
0

Persönlich würde ich es unten wie eine der beiden Optionen schreiben Sie einfach und mit ihm getan werden:

arr.map { |a| a.map(&:next) } 
#=> [[2, 3], [4, 5]] 
arr.map { |x, y| [x.next, y.next] } 
#=> [[2, 3], [4, 5]] 
1
arr.map {|x| x.map(&:succ)} #=> [[2, 3], [4, 5]]