I have data that looks like this:
[
{date: '2014/10/01', group: 'a', node: '2'},
{date: '2014/10/01', group: 'b', node: '3'},
{date: '2014/10/02', group: 'a', node: '4'},
{date: '2014/10/02', group: 'b', node: '1'}
]
How would I go about first grouping by date like so:
.group_by{|x| [x.date.strftime("%Y-%m-%d")}
but then by group
and then node
and render that as a nested json?
I'm looking for something like this:
[
{'2014/10/01': {groups: [{a: ['2'], b: ['3']}]},
{'2014/10/02': {groups: [{a: ['4'], b: ['1']}]},
]
Try this:
arr = [
{date: '2014/10/01', group: 'a', node: '2'},
{date: '2014/10/01', group: 'b', node: '3'},
{date: '2014/10/02', group: 'a', node: '4'},
{date: '2014/10/02', group: 'b', node: '1'}
]
arr.group_by { |item| item[:date] }.map do |k,v|
Hash[k, { groups: v.map { |g| Hash[g[:group], [g[:node]]] }}]
end
# => [{"2014/10/01"=>{:groups=>[{"a"=>["2"]}, {"b"=>["3"]}]}}, {"2014/10/02"=>{:groups=>[{"a"=>["4"]}, {"b"=>["1"]}]}}]
When faced with problems like this one, involving multiple transformations to the data, I often find it useful to divide the problem into two steps, the first being to create an array or hash that contains all the essential information; the second being to format that data in the form desired.
It's best to describe the procedure around an example. The one given in the question is fine:
arr = [
{date: '2014/10/01', group: 'a', node: '2'},
{date: '2014/10/01', group: 'b', node: '3'},
{date: '2014/10/02', group: 'a', node: '4'},
{date: '2014/10/02', group: 'b', node: '1'}
]
As we will be grouping on the date, it makes sense to extract the data from arr
into a hash whose keys are dates. The values of those keys are hashes that contain key-value pairs corresponding to the values of :group
and :node
in each element of arr
. I've chosen to do that using the form of Hash#update (aka merge!
) that uses a block to determine the values of keys that are present in both hashes being merged:
h = arr.each_with_object({}) { |g,h|
h.update(g[:date]=>{ g[:group]=>g[:node] }) { |_,oh,nh|oh.update(nh) } }
#=> {"2014/10/01"=>{"a"=>"2", "b"=>"3"},
# "2014/10/02"=>{"a"=>"4", "b"=>"1"}}
Before moving on to the formatting step, I should point out that, depending on requirements, it may more convenient to use this hash in subsequent calculations, rather than the array requested.
Formatting is now straightforward, using Enumerable#map :
h.map { |d,g| { d=>{groups: [g] } } }
#=> [{"2014/10/01"=>{:groups=>[{"a"=>"2", "b"=>"3"}]}},
# {"2014/10/02"=>{:groups=>[{"a"=>"4", "b"=>"1"}]}}]
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.