Разбор массива хэшей в древовидную структуру - PullRequest
0 голосов
/ 13 декабря 2018

У меня есть такая структура в Ruby:

[
  {“type"=>"Action", "parameterized"=>false, "groups"=>["feed"], "value"=>"feed”},
  {"type"=>"State", "parameterized"=>true, "groups"=>["group"], "value"=>"group:%1s”},
  {"type"=>"Action", "parameterized"=>false, "groups"=>["challenge", "build"], "value"=>"challenge:build”},
  {"type"=>"Action", "parameterized"=>false, "groups"=>["challenge", "decorate"], "value"=>"challenge:decorate”},
  {"type"=>"Action", "parameterized"=>false, "groups"=>["report"], "value"=>"report”},
  {"type"=>"Action", "parameterized"=>false, "groups"=>["report", "complete"], "value"=>"report:complete”},
]

Элементы в массиве могут располагаться в любом порядке, и я хочу, чтобы он был разобран в древовидную структуру, чтобы при наличии соответствующих групп (каждаяМассив groups приходит в том порядке, в котором первый является корнем, а следующий является дочерним по отношению к первому, а следующий снова является дочерним по отношению к предыдущему и т. д.) объединяются в одну и ту же ветвь в дереве.Если есть «параметризованный» параметр, это также приводит к дополнительной ветке в дереве.Я хочу, чтобы приведенная выше структура в итоге выглядела следующим образом:

{
  "Action" => {
    "feed" => {
      "value" => "feed"
    },
    "challenge" => {
      "build" => {
        "value" => "challenge:build"
      }
      "decorate" => {
        "value" => "challenge:decorate"
      }
    },
    "report" => {
      "value" => "report",
      "complete" => {
        "value" => "report:complete"
      }
    }
  },
  "State" => {
    "group" => {
      "parameterized" => {
        "value" => "group:%1s"
      }
    }
  }
}

Любая идея.как это сделать в Ruby?

С уважением
Søren

1 Ответ

0 голосов
/ 13 декабря 2018

Во-первых, давайте определим процедуру, которая будет искать скрытые группы внутри одного типа

deep_find = ->(hash, name) {
  hash.detect { |k, v| k == name || v.is_a?(Hash) && deep_find.(v, name) }
}

Теперь мы готовы пройти по входному хешу, либо добавив хвост к found ключ или вставка нового ключа.

Объекты в Ruby являются изменяемыми, и это нам очень поможет;Обойдя зверя, мы обнаружим необходимый хеш и изменим его на месте.Эти изменения будут отражены в целом.

input.each_with_object(Hash.new { |h, k| h[k] = h.dup.clear }) do |h, acc|
  # let’s dig into the hash and find the _branch_ of interest
  #   it will return the hash _or_ `nil`
  buried = deep_find.(acc[h['type']], '')
  # if the target was found, we pivk it up for further modifications
  #   otherwise we start from the top level
  target = buried ? buried.last : acc[h['type']]
  # going down the tree of groups; each call to `inner[g]`
  #   will produce the nested hash, thanks to `default_proc`
  #   of the accumulator
  target = h['groups'].reduce(target) { |inner, g| inner[g] }
  # determine whether we should wrap the value with `parametrized`
  #   and eventually set it
  (h['parameterized'] ? target['parameterized'] : target)['value'] = h['value']
end
#⇒ {"type1"=>{"group1"=>{"group2"=>{"value"=>"value1",
#      "group7"=>{"group8"=>{"parameterized"=>{"value"=>"value3"}}}}}},
#   "type2"=>{"group3"=>{"group4"=>{"group5"=>{"value"=>"value2"}}}}}

NB Трюк с процедурой по умолчанию аккумулятора (Hash.new { |h, k| h[k] = h.dup.clear }) позволяет не беспокоиться об инициализации новых значений, независимо от того, насколько они глубокиесть.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...