5

How would I do something like below?

[ 'foo' ['bar', 'baz'], [ 'one', ['two', 'three'] ] ].each { |word| puts word } # I want this to return: foo bar baz one two three 
1
  • Should there be a comma after 'foo'? Commented May 10, 2010 at 0:00

3 Answers 3

3

Could you use flatten?

[ 'foo' ['bar', 'baz'], [ 'one', ['two', 'three'] ] ].flatten.each { |word| puts word } 

flatten will return a copy of the array, so the original won't be modified.
It's also fully recursive so it doesn't matter how many arrays-within-arrays you have.

Sign up to request clarification or add additional context in comments.

1 Comment

puts, if given an array, will print each element of the array on a separate line. Therefore, a = [...] ; puts a.flatten can, if desired, replace the each loop.
2

If you don't want to flatten the array and still achieve the desired functionality, you can do something like:

irb(main):016:0> array = [1, [2, 3], [4, [5, 6]]] => [1, [2, 3], [4, [5, 6]]] irb(main):017:0> (traverser = lambda { |list| list.respond_to?(:each) ? list.each(&traverser) : puts(list) })[array] 1 2 3 4 5 6 => [1, [2, 3], [4, [5, 6]]] 

2 Comments

I really like this! This is more of what I was asking for.
No problem! If you want to get more clever, check out: github.com/evansenter/y - an implementation of the Y-combinator in Ruby (note: Most rubies are not tail-call optimized, so with deep nesting this can have performance issues). Then you can: Y([1, [2, 3], [4, [5, 6]]]) { |recurser, list| list.respond_to?(:each) ? list.each(&recurser) : puts(list) } The difference being no variable assignment (a la 'traverser' in the example above). :]
2

The easiest way:

words = ['foo',['bar', 'baz'],['one',['two', 'three']]] words.flatten.each{ |word| puts word } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.