20

I have some simple code that looks like this:

fruit.each do |c|
  c.each do |key, value|
    puts value
  end
end

This works fine, but it feels un-ruby like. My goal is to take this array:

[{"fruit_id"=>"1"}, {"fruit_id"=>"2"}, {"fruit_id"=>"3"}]

And convert it to this:

[ "1", "2", "3" ]

Thoughts?

6 Answers 6

41

If it's in Rails or if you have to_proc defined, you can go a little bit shorter than @toholio's solution:

arr = [{"fruit_id"=>"1"}, {"fruit_id"=>"2"}, {"fruit_id"=>"3"}]
out = arr.map(&:values).flatten # => ["1", "2", "3"]
Sign up to request clarification or add additional context in comments.

3 Comments

I wish I could approve both - this is great too!
Well, they're actually the same solution really. :)
for 1.9.3 there is arr.flat_map(&:values)
21

So you want each hash to be converted to its values then joined with the values from the other hashes?

in = [{"fruit_id"=>"1"}, {"fruit_id"=>"2"}, {"fruit_id"=>"3"}]
out = in.map{ |item| item.values }.flatten

out will then be ["1","2","3"].

Comments

14

@wombleton @aronchick I suggest to use "flat_map(&:values)" instead "map(&:values).flatten" for better performance.

arr = [{"fruit_id"=>"1"}, {"fruit_id"=>"2"}, {"fruit_id"=>"3"}]
out = arr.flat_map(&:values)

Take a look here for more info: http://gistflow.com/posts/578-use-flat_map-instead-of-map-flatten

Comments

5

if you use map!, you don't create another array in memory

a.map! {|h| h.values}.flatten

this can be also written as

a.map!(&:values).flatten!

also looking at the comments, theres a method in ruby 1.9.3 called flat_map (http://ruby-doc.org/core-1.9.3/Enumerable.html#method-i-flat_map) that will do the map and the flatten in one call.

a.flat_map(&:values)

1 Comment

...or at least not use a local variable.
4
a.inject([]) { |mem,obj| mem += obj.values }

3 Comments

injecting into an empty array is also known as collect (or map). see other answers here.
Use << instead of += to append to arrays. It will be slightly faster as you won't be creating all those new array objects.
<< and += are not the same. If you want to use "<<" you will have to flatten again. Anyways its just nitpick.
0

It wouldn't change much, but you could use map:

x.map do |fruit|
    fruit.each { |k,v| puts v }
end

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.