4

I have an array like this:

[{:a=>"2017-01-01", :b=>"2", :c=>"1"}, {:a=>"2017-01-01", :b=>"2", :c=>"2"}, {:a=>"2017-01-02", :b=>"5", :c=>"1"}]

If, for example, I group the array with the key ":a", the result is:

p = y.group_by { |g| g[:a]}

 => {"2017-01-01"=>[{:a=>"2017-01-01", :b=>"2", :c=>"1"}, {:a=>"2017-01-01", :b=>"2", :c=>"2"}], "2017-01-02"=>[{:a=>"2017-01-02", :b=>"5", :c=>"1"}]} 

Now I want to group for each ":a" the key ":b" like:

 => {"2017-01-01"=>["2" => [{:a => "2017-01-01", :b => "2", :c => "1" }], ... }

How can I do? Thanks in advance.

Edit:

multiple group by ... 1° group_by a, 2° group_by b the result of 1°, etc..

y.group_by {|g| g[:a]}.map do |k,v|
 [
  k, v.group_by { |d| d[:b] }.map do |p,q|
   [p, q.group_by { |f| f[:c] }]
  end.to_h
 ]
end.to_h  
1
  • 1. [:a=>... is not a valid Ruby object. Please edit to correct. 2. It's not obvious what ... stands for. Please replace all ... with the values you desire as output for the example. 3. When you give an example (generally) assign a variable to each input object (e.g., arr = [{:a=>...) so that readers can refer to those variables (here just one) in answers and comments without having to define them. Commented Feb 9, 2017 at 19:12

2 Answers 2

7

Quick answer, using your code above:

y = [{:a=>"2017-01-01", :b=>"2", :c=>"1"}, {:a=>"2017-01-01", :b=>"2", :c=>"2"}, {:a=>"2017-01-02", :b=>"5", :c=>"1"}]
p = y.group_by { |g| g[:a]}
q = p.map {|date, list| [date, list.group_by {|g| g[:b]}]}.to_h

This gives the desired result of:

q == {
  "2017-01-01" => {
    "2"=> [
      {:a=>"2017-01-01", :b=>"2", :c=>"1"},
      {:a=>"2017-01-01", :b=>"2", :c=>"2"}
    ]
  },
  "2017-01-02" => {
    "5"=> [
      {:a=>"2017-01-02", :b=>"5", :c=>"1"}
    ]
  }
}

This slightly odd pattern of mapping the hash to a list of arrays, then converting it back to a hash (using to_h) can be simplified slightly if you are working with a Rails v4.2+ project, by use of Hash#transform_values:

p.transform_values {|list| list.group_by {|g| g[:b]}}

However with that said, it is generally considered bad practice to be manipulating complex, nested hash objects like this. If your code gets too complicated, you may wish to consider redesigning how it works, in a more Object-Oriented manner.

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

9 Comments

Thank you very much for the answer.
I would submit to you another question. If I want to add an additional group_by the second filter, how do I proceed?
An additional group_by? Do you mean for a final result like: {"2017-01-01" => { "2"=> {"1" => {:a=>"2017-01-01", :b=>"2", :c=>"1"} ....??
Yes, I would an additional grop_by... I found this solution y.group_by {|g| g[:a]}.map do |k,v| [ k, v.group_by { |d| d[:b] }.map do |p,q| [p, q.group_by { |f| f[:c] }] end.to_h ] end.to_h
Erm... Yes, something like that would work. But please, do note my above comment: "...bad practice to be manipulating complex, nested hash objects... consider redesigning how it works...". There are better ways of handling complex data structures in ruby than big nested hashes!
|
3

I think, a few from possible solutions is:

 y = [
  {
    :a=>"2017-01-01", 
    :b=>"2", 
    :c=>"1"
  }, 
  {
    :a=>"2017-01-01", 
    :b=>"2", 
    :c=>"2"
  }, 
  {
    :a=>"2017-01-02", 
    :b=>"5", 
    :c=>"1"
  }
]

first:

y.group_by { |g| [g[:a], g[:b]] }

but result would seems:

#=> {["2017-01-01", "2"]=>[{:a=>"2017-01-01", :b=>"2", :c=>"1"}, {:a=>"2017-01-01", :b=>"2", :c=>"2"}], ["2017-01-02", "5"]=>[{:a=>"2017-01-02", :b=>"5", :c=>"1"}]}

and second one:

y.group_by { |g| g[:a] }.map do |key, value| 
   [key, value.group_by { |g| g[:b] }] 
end.to_h

#=> {"2017-01-01"=>{"2"=>[{:a=>"2017-01-01", :b=>"2", :c=>"1"}, {:a=>"2017-01-01", :b=>"2", :c=>"2"}]}, "2017-01-02"=>{"5"=>[{:a=>"2017-01-02", :b=>"5", :c=>"1"}]}}

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.