#ruby #hash
#ruby #хэш
Вопрос:
Привет всем, я сделал себе довольно сложную (по крайней мере, для меня) конструкцию. У меня есть хэш, выглядящий как (пример):
states_with_depths = {
#State => depth
"S0" => 0,
"S1" => 1,
"S2" => 2,
"S3" => 2,
"S4" => 2,
"S5" => 3
}
(примечание: это хэш, поэтому он еще не отсортирован)
Теперь, что я хотел бы: иметь цикл, начинающийся с depth = 0, с набором всех состояний, имеющих глубину 0 или меньше, следующую итерацию цикла, имеющую набор всех состояний с глубиной 1 или меньше и т.д.
Каким был бы аккуратный способ получить такую конструкцию?
Пожалуйста, дайте мне знать, если мой вопрос неясен.
Ответ №1:
Вы можете просто использовать group_by
со значением:
>> states_with_depths.group_by { |k,v| v }
#=> {0=>[["S0", 0]], 1=>[["S1", 1]], 2=>[["S2", 2], ["S3", 2], ["S4", 2]], 3=>[["S5", 3]]}
Это также можно сократить до:
states_with_depths.group_by(amp;:last)
Чтобы использовать это, вы можете сделать что-то вроде:
states_with_depths.group_by(amp;:last).each do |depth, arrs|
puts "Values with depth #{depth}: #{arrs.map(amp;:first)}"
end
Который выводит:
Values with depth 0: ["S0"]
Values with depth 1: ["S1"]
Values with depth 2: ["S2", "S3", "S4"]
Values with depth 3: ["S5"]
Комментарии:
1. Спасибо, я протестировал это, и это отлично работает! Я придерживаюсь решения J-.-L, потому что его результат ближе к тому, что мне было нужно
2. примечание: я не смог отредактировать ваш комментарий, но после него есть дополнительный «}»
(amp;:first)}"
3. Да, спасибо. Я переписал это из
{}
блока do ado...end
one, потому что здесь легче читать, а затем забыл эту фигурную скобку.4. Кстати: Это
states_with_depths.group_by(amp;:last).map { |d, arr| arr.map(amp;:first) }
также должно предоставить то, что вам нужно. 🙂
Ответ №2:
require 'set'
depths_with_states = []
max_level = states_with_depths.max_by{|e|e[1]}[1]
states_with_depths.map{ |state, level|
(level..max_level).each{ |i|
depths_with_states[i] ||= Set.new # ...or just array
depths_with_states[i] << state
}
}
depths_with_states.each{ |states|
# do whatever you want to do ;)
}
Комментарии:
1. В коде ошибка: выполнение
(0..level).each { |i| ..
приводит к тому, что depths_with_states[i] имеет набор всех состояний с глубиной i вместо 0 ..i
Ответ №3:
Вот вариант, который работал для Ruby до версии 1.8.7 (когда Enumerable#group_by
был добавлен):
states_by_depth = Hash.new{|h,depth| h[depth]=[] }
states_with_depths.each{ |state,depth| states_by_depth[depth] << state }
#=> {0=>["S0"], 1=>["S1"], 2=>["S3", "S4", "S2"], 3=>["S5"]}
min_depth = states_by_depth.keys.min
max_depth = states_by_depth.keys.max
min_depth.upto(max_depth) do |depth|
next unless states = states_by_depth[depth]
puts "Depth: #{depth}"
states.each{ |state| puts "..#{state}" }
end
#=> Depth: 0
#=> ..S0
#=> Depth: 1
#=> ..S1
#=> Depth: 2
#=> ..S3
#=> ..S4
#=> ..S2
#=> Depth: 3
#=> ..S5