ruby picture

RCR 244: Limit recursion depth of Array#flatten

Submitted by matthias_georgi (Tue Apr 13 08:04:08 UTC 2004)

Abstract

Let Array#flatten and Array#flatten! take an argument, which limits the recursion depth of flattening.

Problem

If you want
[ [:a, 1], [:b, [2, 3]] ] to result in

[ :a, 1, :b, [2, 3] ]

, Array#flatten is not appropiate.

This is useful for making Hashs like:

module Enumerable
  def make_hash(&block)
    Hash[* map(&block).flatten(1) ]
  end
end

This way one can return a tuple in each iteration as [key, value] pair.

Proposal

Array#flatten takes one integer argument and stops the recursion if desired depth is reached. The default is set to -1, which means no limit. A value of 1 only flattens the first level and leaves deeper levels untouched.

Analysis

This Change doesn't break existing code and would allow much faster Hash creation in combination with something like make_hash. It is useful in all cases, when someone wants to expand an Array as result of a block with nested Arrays preserved.

Implementation

Implementation is easy.
In array.c flatten(), rb_ary_flatten_bang(), rb_ary_flatten() need one additional limit argument.
flatten() returns if limit is 0 or decrease limit by one.
ruby picture
Comments Current voting

The 'flattenx' package on RAA does exactly this. I put it there two or three years ago, and I've never heard anyone mention having used it, which may mean that this is not a popular concept (or it may mean that the "Ruby doesn't have any libraries" cliche has once again prevailed and stopped people from realizing that there is a lot out there).

In any case, I tend to think it should be a different method name, like flatten_by(x), but I definitely like the idea.

-- David Black


In Ruby it's just a three-liner, which takes less time than starting a webbrowser. I think such features should be at least in the standard library, to become common practice. Beyond that, converting arrays efficiently into hashs is a core language aspect. While thinking about it, i realize, it is maybe better to have a pendant to Hash#to_a. There exist some similar symmetries in Ruby like 10.to_s.to_i . I do know only Hash[*list], but Array#to_h would make more sense with tuples, which makes the flatten call in the RCR example above obsolete.

-- Matthias Georgi


For the record, 'flattenx' is neither a three-liner nor in Ruby; it's in C, for speed. I don't agree in a general sense that everything that either is potentially useful or is a candidate for speed should be in the core language. But I still would like to see #flatten_by(n) or equivalent.

I'm not sure what you mean by 'a pendant to Hash#to_a' -- can you explain? #to_h has been under discussion/debate for a long time.... see ruby-talk archives (if you have time and patience :-)

-- David Black


I read the thread started by Gavin Sinclair, which lead to RCR #148. I don't like it, because you cannot insert keys from a block, so not flexible enough.

I understand the point of error handling. Maybe, to_h should treat non-two-element-arrays like follows: [ :a, [:b], [:c, :d], [:e, :g, :h] ].to_h => { :a => nil, :b => nil, :c => :d, :e => g } So each array element gives one key at least.

But that's maybe too confusing, so flatten_by() would be better.

Such little things as C-Extensions aren't very convenient, if you have many of them a ruby installation with a full set of libraries will get complicated and dependant, to put flattenx into ext/ is also not the best solution, because of code duplication.

-- Matthias Georgi


Strongly opposed 0
Opposed 0
Neutral 1
In favor 9
Strongly advocate 8
ruby picture
If you have registered at RCRchive, you may now sign in below. If you have not registered, you may sign up for a username and password. Registering enables you to submit new RCRs, and vote and leave comments on existing RCRs.
Your username:
Your password:

ruby picture

Powered by .