/ / Classificar itens em um hash aninhado por seus valores - ruby, classificação

Classificar itens em um hash aninhado por seus valores - ruby, classificação

Estou sendo enviado um hash aninhado que precisa ser classificado por seus valores. Por exemplo:

@foo = {"a"=>{"z"=>5, "y"=>3, "x"=>88}, "b"=>{"a"=>2, "d"=>-5}}

Ao executar o seguinte:

@foo["a"].sort{|a,b| a[1]<=>b[1]}

Eu recebo:

[["y", 3], ["z", 5], ["x", 88]]

Isso é ótimo, é exatamente o que eu quero. O problema é que nem sempre vou saber quais são todas as chaves que estão sendo enviadas para mim, então preciso de algum tipo de loop. Eu tentei fazer o seguinte:

@foo.each do |e|
e.sort{|a,b| a[1]<=>b[1]}
end

Isso faz sentido para mim, pois se eu ligar manualmente para @ foo.first [0], recebo

"a"

e @ foo.first [1] retorna

{"z"=>5, "y"=>3, "x"=>8}

mas, por algum motivo, isso não está sendo organizado corretamente(por exemplo). Suponho que isso ocorra porque cada um está chamando a classificação no objeto hash inteiro, e não nos valores de "a". Como acesso os valores do hash aninhado sem saber qual é a chave?

Respostas:

6 para resposta № 1

Você pode fazer um loop sobre o hash assim:

@ foo.each do | chave, valor | @foo [chave] = valor.sort {| a, b | a [1] <=> b [1]} fim

4 para resposta № 2
@foo = {"a"=>{"z"=>5, "y"=>3, "x"=>88}, "b"=>{"a"=>2, "d"=>-5}}
@bar = Hash[ @foo.map{ |key,values| [ key, values.sort_by(&:last) ] } ]

Ou, por um caminho menos complicado:

@bar = {}
@foo.each do |key,values|
@bar[key] = values.sort_by{ |key,value| value }
end

Em ambos os casos @bar acaba por ser:

p @bar
#=> {
#=>   "a"=>[["y", 3], ["z", 5], ["x", 88]],
#=>   "b"=>[["d", -5], ["a", 2]]
#=> }

1 para resposta № 3

Meu colega de trabalho apresentou uma solução um pouco mais flexível que classifica recursivamente uma matriz de qualquer profundidade:

def deep_sort_by(&block)
Hash[self.map do |key, value|
[if key.respond_to? :deep_sort_by
key.deep_sort_by(&block)
else
key
end,

if value.respond_to? :deep_sort_by
value.deep_sort_by(&block)
else
value
end]

end.sort_by(&block)]
end

Você pode injetá-lo em todos os hashes e então chamar assim:

myMap.deep_sort_by { |obj| obj }

O código seria semelhante para uma matriz. Nós publicou como uma jóia para outros usarem, consulte postagem no blog para detalhes adicionais.

Disclaimer: Eu trabalho para esta empresa.


0 para a resposta № 4

no seu exemplo e é uma matriz temporária que contém um par [chave, valor]. Nesse caso, a chave de caractere e o hash aninhado. então e.sort{|a,b|...} tentará comparar o caractere com o hash e falhará com um erro de tempo de execução. Eu acho que você provavelmente quis digitar e[1].sort{...}. Mas mesmo isso não funcionará corretamente, porque você não armazena o hash classificado em nenhum lugar: @foo.each retorna o @foo original e o deixa inalterado.

A melhor solução é a sugerida por @Pan Thomakos:

@foo.each do |key, value|
@foo[key] = value.sort{ |a,b| a[1]<=>b[1] }
end