5

I have a array of hashes like this:

[ {:foo=>2, :date=>Sat, 01 Sep 2014},
 {:foo2=>2, :date=>Sat, 02 Sep 2014},
 {:foo3=>3, :date=>Sat, 01 Sep 2014},
 {:foo4=>4, :date=>Sat, 03 Sep 2014},
  {:foo5=>5, :date=>Sat, 02 Sep 2014}]

And I want to merge hashes if the :date are same. What I expect from the array above is:

[ {:foo=>2, :foo3=>3, :date=>Sat, 01 Sep 2014},
 {:foo2=>2, :foo5=>5 :date=>Sat, 02 Sep 2014},
 {:foo4=>4, :date=>Sat, 03 Sep 2014}]

How can I do it?

Maybe should I reconsider data structure itself? For example should I use date value as a key of hash?

2
  • No, it's Date class. why? Commented Dec 2, 2014 at 12:41
  • Your hash definitions aren't valid. It's important that they be reusable when we try to help you, so make sure that Ruby will accept them. Commented Dec 2, 2014 at 20:02

2 Answers 2

8

Here's how you could do it in a line (demo):

hashes.group_by{|h| h[:date] }.map{|_, hs| hs.reduce(:merge)}

This code does the following:

  • groups all hashes by their :date value
  • for each :date group, takes all hashes in it and merges them all into one hash

EDIT: Applied modifications suggested by tokland and Cary Swoveland. Thanks!

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

3 Comments

nit-picking: hashes.group_by { |h| h[:date] }.map { |k, hs| hs.reduce(:merge) }
Nice solution. You might consider |_,hs| to tell the reader you're not using the key in the block. It's a pretty small block, so that may be obvious, but still...
Little gotcha - If :date isn't a symbol use 'date'
0

You could make use of the form of Hash#update (a.k.a. merge!) that uses a block to resolve the values of keys that are contained in both of the hashes being merged.

arr = [ {:foo=>2, :date=>'Sat, 01 Sep 2014'},
        {:foo2=>2, :date=>'Sat, 02 Sep 2014'},
        {:foo3=>3, :date=>'Sat, 01 Sep 2014'},
        {:foo4=>4, :date=>'Sat, 03 Sep 2014'},
        {:foo5=>5, :date=>'Sat, 02 Sep 2014'}]

arr.each_with_object({}) do |g,h|
  h.update({ g[:date]=>g }) { |_,o,n| o.merge(n) }
end.values
  #=> [{:foo=>2,  :date=>"Sat, 01 Sep 2014", :foo3=>3},
  #    {:foo2=>2, :date=>"Sat, 02 Sep 2014", :foo5=>5},
  #    {:foo4=>4, :date=>"Sat, 03 Sep 2014"}]

I've used a placeholder _ for the block variable containing the value of the key since it it not used in the block.

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.