Как найти наибольшее значение ха sh в массиве хешей - PullRequest
0 голосов
/ 23 февраля 2020

В моем массиве я пытаюсь получить ключ с наибольшим значением «value_2», поэтому в этом случае «B»:

myArray = [
  "A" => {
    "value_1" => 30,
    "value_2" => 240
  },
  "B" => {
    "value_1" => 40,
    "value_2" => 250
  },
  "C" => {
    "value_1" => 18,
    "value_2" => 60
  }
]

myArray.each do |array_hash|
 array_hash.each do |key, value|
  if value["value_2"] == array_hash.values.max
   puts key
  end
 end
end

Я получаю ошибку:

"comparison of Hash with Hash failed (ArgumentError)".  

Чего мне не хватает?

Ответы [ 5 ]

1 голос
/ 23 февраля 2020

Хотя эквивалентно, массив, приведенный в вопросе, обычно пишется:

arr = [{ "A" => { "value_1" => 30, "value_2" => 240 } },
       { "B" => { "value_1" => 40, "value_2" => 250 } },
       { "C" => { "value_1" => 18, "value_2" =>  60 } }]

Мы можем найти нужный ключ следующим образом:

arr.max_by { |h| h.values.first["value_2"] }.keys.first
  #=> "B"

См. Enumerable # max_by . Шаги:

g = arr.max_by { |h| h.values.first["value_2"] }
  #=> {"B"=>{"value_1"=>40, "value_2"=>250}} 
a = g.keys
  #=> ["B"] 
a.first
  #=> "B" 

При вычислении g для

h = arr[0]
  #=> {"A"=>{"value_1"=>30, "value_2"=>240}}

вычисление блока составляет

a = h.values
  #=> [{"value_1"=>30, "value_2"=>240}] 
b = a.first
  #=> {"value_1"=>30, "value_2"=>240} 
b["value_2"]   
  #=> 240 

Предположим, сейчас arr выглядит следующим образом:

arr << { "D" => { "value_1" => 23, "value_2" => 250 } }
  #=> [{"A"=>{"value_1"=>30, "value_2"=>240}},
  #    {"B"=>{"value_1"=>40, "value_2"=>250}},
  #    {"C"=>{"value_1"=>18, "value_2"=>60}},
  #    {"D"=>{"value_1"=>23, "value_2"=>250}}] 

и мы будем sh возвращать массив всех ключей, для которых значение "value_2" является максимальным (["B", "D"]). Мы можем получить это следующим образом.

max_val = arr.map { |h| h.values.first["value_2"] }.max
  #=> 250
arr.select { |h| h.values.first["value_2"] == max_val }.flat_map(&:keys)
  #=> ["B", "D"]

flat_map(&:keys) - сокращение от:

flat_map { |h| h.keys }

, которое возвращает тот же массив, что и:

map { |h| h.keys.first }

См. перечислимых # flat_map .

0 голосов
/ 24 февраля 2020

Вы спросили: «Чего мне не хватает?».

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

Самый простой способ - p myArray, который дает:

[{"A"=>{"value_1"=>30, "value_2"=>240}, "B"=>{"value_1"=>40, "value_2"=>250}, "C"=>{"value_1"=>18, "value_2"=>60}}]

Вы можете получить более привлекательные результаты, используя pp:

require 'pp'
pp myArray

выход:

[{"A"=>{"value_1"=>30, "value_2"=>240},
  "B"=>{"value_1"=>40, "value_2"=>250},
  "C"=>{"value_1"=>18, "value_2"=>60}}]

Это поможет вам увидеть, что myArray имеет только один элемент, Ха sh.

Вы Можно также посмотреть на выражение array_hash.values.max внутри l oop:

myArray.each do |array_hash|
  p array_hash.values
end

дает:

[{"value_1"=>30, "value_2"=>240}, {"value_1"=>40, "value_2"=>250}, {"value_1"=>18, "value_2"=>60}]

Не то, что вы ожидали? : -)

Учитывая это, что вы ожидаете получить array_hash.values.max в приведенном выше l oop?

Использование p и / или pp в вашем ruby код, помогающий понять, что происходит.

0 голосов
/ 24 февраля 2020

Я бы использовал:

my_array = [
  "A" => {
    "value_1" => 30,
    "value_2" => 240
  },
  "B" => {
    "value_1" => 40,
    "value_2" => 250
  },
  "C" => {
    "value_1" => 18,
    "value_2" => 60
  }
]

h = Hash[*my_array] 
# => {"A"=>{"value_1"=>30, "value_2"=>240},
#     "B"=>{"value_1"=>40, "value_2"=>250},
#     "C"=>{"value_1"=>18, "value_2"=>60}}

k = h.max_by { |k, v| v['value_2'] }.first # => "B"

Hash[*my_array] берет массив хешей и превращает его в один ха sh. Затем max_by будет выполнять итерацию каждой пары ключ / значение, возвращая массив, содержащий значение ключа "B" и вложенный элемент sh, что упрощает захват ключа с помощью first:

k = h.max_by { |k, v| v['value_2'] } # => ["B", {"value_1"=>40, "value_2"=>250}]
0 голосов
/ 23 февраля 2020

Полагаю, идея вашего решения состоит в том, чтобы пройтись по каждому элементу ha sh и сравнить найденное минимальное значение с hash["value_2"].

Но вы получаете сообщение об ошибке на

if value["value_2"] == array_hash.values.max

Поскольку array_hash.values по-прежнему ха sh

{"A"=>{"value_1"=>30, "value_2"=>240}}.values.max 
#=> {"value_1"=>30, "value_2"=>240}

Это должно быть так:

max = nil
max_key = ""
myArray.each do |array_hash|
  array_hash.each do |key, value|
    if max.nil? || value.values.max > max
      max = value.values.max
      max_key = key
    end
  end
end

# max_key #=> "B"

Другое решение:

myArray.map{ |h| h.transform_values{ |v| v["value_2"] } }.max_by{ |k| k.values }.keys.first
0 голосов
/ 23 февраля 2020

Код

p myArray.pop.max_by{|k,v|v["value_2"]}.first

Выход

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