Каков наилучший способ преобразовать хэш ruby ​​в массив - PullRequest
5 голосов
/ 16 апреля 2009

У меня есть рубиновый хеш, который выглядит так

{ "stuff_attributes" => {
     "1" => {"foo" => "bar", "baz" => "quux"}, 
     "2" => {"foo" => "bar", "baz" => "quux"} 
   }
}

и я хочу превратить его в хеш, который выглядит следующим образом

{ "stuff_attributes" => [
    { "foo" => "bar", "baz" => "quux"},
    { "foo" => "bar", "baz" => "quux"}
  ]
}

Мне также нужно сохранить числовой порядок клавиш, и есть переменное количество клавиш. Выше очень упрощенный, но я включил реальный пример внизу. Какой лучший способ сделать это?

P.S

Он также должен быть рекурсивным

Что касается рекурсии, вот что мы можем предположить:

1) ключ, которым нужно манипулировать, будет соответствовать / _attributes $ / 2) хеш будет иметь много других ключей, которые не соответствуют / _attributes $ / 3) ключи внутри хеша всегда будут числом 4) хеш _attributes может находиться на любом уровне хеша под любым другим ключом

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

{
    "commit"=>"Save", 
    "tdsheet"=>{
    "team_id"=>"43", 
    "title"=>"", 
    "performing_org_id"=>"10", 
    "tdsinitneed_attributes"=>{ 
        "0"=>{
            "title"=>"", 
            "need_date"=>"", 
            "description"=>"", 
            "expected_providing_organization_id"=>"41"
            }, 
        "1"=>{
            "title"=>"", 
            "need_date"=>"", 
            "description"=>"", 
            "expected_providing_organization_id"=>"41"
            }
        }, 
        "level_two_studycollection_id"=>"27", 
        "plan_attributes"=>{
            "0"=>{
                "start_date"=>"", "end_date"=>""
            }
        }, 
        "dataitem_attributes"=>{
            "0"=>{
                "title"=>"", 
                "description"=>"", 
                "plan_attributes"=>{
                    "0"=>{
                        "start_date"=>"", 
                        "end_date"=>""
                        }
                    }
                }, 
            "1"=>{
                "title"=>"", 
                "description"=>"", 
                "plan_attributes"=>{
                    "0"=>{
                        "start_date"=>"", 
                        "end_date"=>""
                        }
                    }
                }
            }
        }, 
    "action"=>"create", 
    "studycollection_level"=>"", 
    "controller"=>"tdsheets"
}

Ответы [ 3 ]

8 голосов
/ 16 апреля 2009

Обратите внимание, что может потребоваться много времени, чтобы проверить, являются ли все ключи числами перед преобразованием ...

def array_from_hash(h)
  return h unless h.is_a? Hash

  all_numbers = h.keys.all? { |k| k.to_i.to_s == k }
  if all_numbers
    h.keys.sort_by{ |k| k.to_i }.map{ |i| array_from_hash(h[i]) }
  else
    h.each do |k, v|
      h[k] = array_from_hash(v)
    end
  end
end
4 голосов
/ 16 апреля 2009

Если мы можем предположить, что все ключи на самом деле являются строками, которые преобразуются чисто в целые числа, должно работать следующее:

# "hash" here refers to the main hash in your example, since you didn't name it
stuff_hash = hash["stuff"]
hash["stuff"] = stuff_hash.keys.sort_by {|key| key.to_i}.map {|key| stuff_hash[key]}
0 голосов
/ 05 октября 2015

Чтобы получить немного свободы, я публикую очень похожий пример кода для Винсента Роберта.

Это исправление класса Hash методом .to_array.

 class Hash
   def to_array(h = self)
     return h unless h.is_a? Hash
     if h.keys.all? { |k| k.to_i.to_s == k } # all keys are numbers so make an array.
       h.keys.sort_by{ |k| k.to_i }.map{ |i| self.to_array(h[i]) }
     else
       h.each do |k, v|
         h[k] = self.to_array(v)
       end
     end
   end
 end

Это делает использование немного более удобным.

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