Coda Chang Coda Chang - 2 months ago 12
Ruby Question

Rails how to group by nested hash

I have no clue to solve this question. I got a

nested
hash
inside an
array
called
data
. Here is its structure.

data =
[
{
:id => 1,
:name => "S1",
:children => [
{
:id => 10,
:name => "S10",
:children => [
{
:id => 20,
:name => "S20"
}
]
}
]
},
{
:id => 1,
:name => "S1",
:children => [
{
:id => 10,
:name => "S10",
:children => [
{
:id => 21,
:name => "S21"
}
]
}
]
},
{
:id => 1,
:name => "S1",
:children => [
{
:id => 11,
:name => "S11",
:children => [
{
:id => 22,
:name => "S22"
}
]
}
]
}
]


As you can see, there are bunch of elements which have the same
id
in the first layer or second layer, so I need to group them.

I hope the result will be

result=
[
{
:id => 1,
:name => "S1",
:children => [
{
:id => 10,
:name => "S10",
:children => [
{
:id => 20,
:name => "S20"
},
{
:id => 21,
:name => "S21"
}
]
},
{
:id => 11,
:name => "S11",
:children => [
{
:id => 22,
:name => "S22"
}
]
}
]
}
]


I've tried somthing like

data.group_by{|s| s[:id]}


However, it would only group the first layer, I don't know how to group nested structure.

Answer

Yeah you need some kind of recursive method to recursively combine and group the nested children.

This produces the result you want:

def group(data)
  r = {}
  # Combine the children
  data.each do |d| 
    if r[d[:id]]
      r[d[:id]][:children] += d[:children]
    else
      r[d[:id]] = d
    end
  end
  # Now group the children
  r.values.map do |d|
    d[:children] = group(d[:children]) if d[:children]
    d
  end
end
Comments