Предполагая, что глубина установлена равной 3, а правила согласованы (как показано в примере), вы можете сделать это однопроходным преобразованием следующим образом:
h.each_with_object(Hash.new {|h,k| h[k]= {}}) do |(k,v),obj|
new_k, k2, k3 = k[/(?<=builder_rule_).*/].split('_')
k2 == 'value' ? (obj[new_k]["values"] ||= {}).merge!({k3 => v}) : obj[new_k][k2] = v
end
Здесь мы создаем новый Hash
где ключи первого уровня по умолчанию пустые Hash
(h.each_with_object(Hash.new {|h,k| h[k]= {}}) do |(k,v),obj|
).
Затем мы разделяем ключ на основе подчеркивания после 'builder_rule_' new_k, k2, k3 = k[/(?<=builder_rule_).*/].split('_')
Тогда, еслиКлюч второго уровня (k2) равен значению, нам нужно сделать его значениями и объединить ключ третьего уровня (k3) и значение в новый хеш, в противном случае мы присваиваем значение k2.k2 == 'value' ? (obj[new_k]["values"] ||= {}).merge!({k3 => v}) : obj[new_k][k2] = v
Это фактически вернет запрошенное требование, где values
- это Hash
с ключевыми индексами
{
"0"=>{
"filter"=>"artist_name",
"operator"=>"contains",
"values"=>
{
"0"=>"New Found Glory"
}
},
"1"=>{
"filter"=>"bpm",
"operator"=>"less",
"values"=>
{
"0"=>"150"
}
},
"2"=>{
"filter"=>"days_ago",
"operator"=>"less",
"values"=>
{
"0"=>"40"
}
},
"3"=>{
"filter"=>"release_date_start",
"operator"=>"between",
"values"=>
{
"0"=>"2019-01-01",
"1"=>"2019-12-31"
}
}
}