Сортировать элементы во вложенном хэше по их значениям - PullRequest
7 голосов
/ 07 февраля 2011

Мне отправляют вложенный хэш, который нужно отсортировать по его значениям.Например:

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

При выполнении следующего:

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

Я получаю:

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

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

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

Для меня это имеет смысл, поскольку, если я вручную вызываю @ foo.first [0], я получаю

"a"

и @ foo.first [1] возвращает

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

, но по какой-то причине это неправильно сортируется (например, вообще).Я предполагаю, что это потому, что каждый вызывает сортировку по всему хеш-объекту, а не по значениям "a".Как получить доступ к значениям вложенного хэша, не зная, что это за ключ?

Ответы [ 4 ]

6 голосов
/ 07 февраля 2011

Возможно, вы захотите перебрать хеш следующим образом:

@foo.each do |key, value|
  @foo[key] = value.sort{ |a,b| a[1]<=>b[1] }
end
4 голосов
/ 07 февраля 2011
@foo = {"a"=>{"z"=>5, "y"=>3, "x"=>88}, "b"=>{"a"=>2, "d"=>-5}}
@bar = Hash[ @foo.map{ |key,values| [ key, values.sort_by(&:last) ] } ]

Или по менее сложному пути:

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

В обоих случаях @bar оказывается:

p @bar
#=> {
#=>   "a"=>[["y", 3], ["z", 5], ["x", 88]],
#=>   "b"=>[["d", -5], ["a", 2]]
#=> }
1 голос
/ 31 августа 2016

Мой коллега предложил немного более гибкое решение, которое будет рекурсивно сортировать массив любой глубины:

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

. Вы можете вставить его во все хэши, а затем просто вызвать его так:

myMap.deep_sort_by { |obj| obj }

Код будет похож на массив.Мы опубликовали его как драгоценный камень , чтобы другие могли его использовать, см. сообщение в блоге для получения дополнительной информации.

Отказ от ответственности: я работаю в этой компании.

0 голосов
/ 07 февраля 2011

в вашем примере e - это временный массив, содержащий пару [ключ, значение]. В этом случае символьный ключ и вложенный хеш. Поэтому e.sort{|a,b|...} попытается сравнить символ с хешем и завершится неудачно с ошибкой во время выполнения. Я думаю, что вы, вероятно, хотели напечатать e[1].sort{...}. Но даже это не будет работать правильно, потому что вы нигде не храните отсортированный хеш: @foo.each возвращает исходный @foo и оставляет его без изменений.

Лучшее решение - предложенное @Pan Thomakos:

@foo.each do |key, value|
  @foo[key] = value.sort{ |a,b| a[1]<=>b[1] }
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...