81

I have an array of arrays in Ruby on Rails (3.1) where all the internal arrays are of different size. Is there a way to easily concatenate all the internal arrays to get one big one dimesional array with all the items?

I know you can use the Array::concat function to concatenate two arrays, and I could do a loop to concatenate them sequentially like so:

concatenated = Array.new
array_of_arrays.each do |array|
    concatenated.concat(array)
end

but I wanted to know if there was like a Ruby one-liner which would do it in a cleaner manner.

Thanks for your help.

Sparhawk
  • 1,581
  • 1
  • 19
  • 29
Pedro Cori
  • 2,046
  • 2
  • 16
  • 23
  • 1
    As suggested, `flatten(1)` is what you want, but I wanted to point out that you could write what you have above as `array_of_arrays.reduce(:concat)`. – Cary Swoveland Apr 02 '15 at 07:32

3 Answers3

183

You're looking for #flatten:

concatenated = array_of_arrays.flatten

By default, this will flatten the lists recursively. #flatten accepts an optional argument to limit the recursion depth – the documentation lists examples to illustrate the difference.

millimoose
  • 39,073
  • 9
  • 82
  • 134
  • 24
    Better `flatten(1)`. Elements in array could be array themselves and they would be recursively flattened. – tokland Nov 27 '11 at 00:01
  • the optional argument requires Ruby 1.8.7 or higher by the way – user102008 Dec 13 '13 at 09:45
  • Also as a general suggestion; it would be recommended to use `flatten!(n)` as this modifies the object in place instead of making a copy of it. Using methods that alter objects in place can be more performant by reducing the amount of GC needed to be done. – ARun32 Apr 19 '19 at 05:05
  • 1
    1. This is pretty potent necromancy :D 2. I wouldn't make it a *general* recommendation, especially now that functional programming is a meme. But even disregarding that, I'd argue that *generally* clobbering inputs bad, referential transparency good, and one should use bang methods as an optimization where the observable result is the same as if you used a copy unless you have program logic based reasons to want to expose the in-place mutation. – millimoose Apr 21 '19 at 14:31
30

Or more generally:

array_of_arrays.reduce(:concat)
d11wtq
  • 34,788
  • 19
  • 120
  • 195
  • This will not destroy 3, 4 or 5+ dimensional arrays in the way that flatten will ;) With `#flatten`, you need to be very aware of what your arrays contain, as it is a recursive method, which may or may not be desirable. – d11wtq Nov 26 '11 at 23:32
  • Ah, ok. I'll keep that in mind when I use it for something like that. In this case it wasn't very important, as they were simple arrays and recursive works fine. – Pedro Cori Nov 26 '11 at 23:54
  • @d11wtq: that's true, that why Ruby 1.9 has `flatten(n)` – tokland Nov 27 '11 at 00:02
  • 2
    Note that this code will alter the original `array_of_arrays` which could cause issues if you still plan to use the original array elsewhere. – mkataja Oct 04 '16 at 10:52
  • To avoid altering the original, you can do `array_of_arrays.reduce :+`. But note that both of these return `nil` if `array_of_arrays` is empty, whereas `flatten` returns `[]`. – Tim Smith May 28 '20 at 16:43
5

You can use flatten! method. eg. a = [ 1, 2, [3, [4, 5] ] ] a.flatten! #=> [1, 2, 3, 4, 5]

Pankaj
  • 150
  • 1
  • 6
  • By using `a.flatten!` you also prevent making a duplicate of the array, saving memory and garbage collection. – ARun32 Apr 19 '19 at 05:08