RUBY - Найти наиболее распространенное название лекарства в массиве хэшей - PullRequest
0 голосов
/ 12 февраля 2019

Мне нужно получить наиболее частое название лекарства в массиве хэшей.

Данные массива:

Medicine.create([{name: "Apixibucil", patient_id: 1, review_id: 17, nurse_id: 2},
  {name: "Adriacilin", patient_id: 1, review_id: 17, nurse_id: 12},
  {name: "Tiaferol", patient_id: 4, review_id: 2, nurse_id: 17},
  {name: "Afalinum", patient_id: 6, review_id: 7, nurse_id: 10},
  {name: "Afalinum", patient_id: 9, review_id: 9, nurse_id: 9},
  {name: "Afalinum", patient_id: 22, review_id: 13, nurse_id: 1}])

Код, который я написал, - (Метод является частьюCLI, поэтому я включил его):

def most_common_medicine_on_study
  puts "Do you want to know the most popular medicine in the study?"
  puts ">"
  input = gets.chomp
  if input == "yes" || "y"
    Medicine["data"].each do |meds|
      meds["name"].max_by {|name| name.length}
    end
  end
end

Ответы [ 2 ]

0 голосов
/ 12 февраля 2019

Вот решение.

Medicine['data'].reduce Hash.new(0) do |count, med|
  count[med[:name]] += 1
  count
end.max_by(&:last)

#=> ["Afalinum", 3]

1) Уменьшите хэш, где все значения по умолчанию равны 0.

2) Подсчитайте вхождение каждого имени медика.

3) Возврат наибольшего значения из счетчика.

Бенчмарк

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

benchmarker do
  result = data.reduce Hash.new(0) do |count, med|
    count[med[:name]] += 1
    count
  end.max_by(&:last)

  puts result
end
#=> [Afalinum, 1500000]
#=> {"ruby":"2.5.1","elapsed_time":0.72,"garbage_collection":"on","memory_used":"0 MB","garbage_collection_count":1}

benchmarker do
  result = data.each_with_object(Hash.new(0)) { |h, o| o[h[:name]] += 1 }.max_by { |_, v| v }

  puts result
end
#=> [Afalinum, 1500000]
#=> {"ruby":"2.5.1","elapsed_time":0.72,"garbage_collection":"on","memory_used":"0 MB","garbage_collection_count":1}

benchmarker do
  result = data.group_by { |h| h[:name] }.transform_values { |v| v.size}.max_by { |_, v| v }

  puts result
end
#=> [Afalinum, 1500000]
#=> {"ruby":"2.5.1","elapsed_time":0.52,"garbage_collection":"on","memory_used":"18 MB","garbage_collection_count":2}

Мне было интересно узнать, что подход group_by на самом деле обрабатывает вычисления быстрее, хотя и использует изрядное количество памяти.сделать это.Первыми, кто выполнил буквально то же самое, разработчик может сами выбирать, что ему удобнее читать.

0 голосов
/ 12 февраля 2019

Используя допустимый массив Ruby:

medicine = [{name: "Apixibucil", patient_id: 1, review_id: 17, nurse_id: 2},
            {name: "Adriacilin", patient_id: 1, review_id: 17, nurse_id: 12},
            {name: "Tiaferol", patient_id: 4, review_id: 2, nurse_id: 17},
            {name: "Afalinum", patient_id: 6, review_id: 7, nurse_id: 10},
            {name: "Afalinum", patient_id: 9, review_id: 9, nurse_id: 9},
            {name: "Afalinum", patient_id: 22, review_id: 13, nurse_id: 1}]

Вы можете использовать Enumerable#group_by и Hash#transform_values:

medicine.group_by{ |h| h[:name] }.transform_values { |v| v.size}.max_by { |_, v| v }

Или с помощью Enumerable#each_with_object с использованием Hash#new по умолчанию 0, чтобы считать:

medicine.each_with_object(Hash.new(0)) { |h, o| o[h[:name]] += 1 }.max_by { |_, v| v }

В обоих случаях используется Enumerable#max_by, чтобы получить максимальное количество, возвращая:

["Afalinum", 3]


Если вы используете Rails, проверьте вычисления , возможно, вы можете сделать:
Medicine.group(:name).count
# => { 'Apixibucil' => 1, 'Adriacilin' => 1, 'Tiaferol' => 1, 'Afalinum' => 3 }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...