Как выполнить переупорядочение массива массивов хэшей в ruby

#arrays #ruby-on-rails #ruby #hash

Вопрос:

У меня есть массив, как показано ниже:

 product = [[{:pm=>61, :scs=>20,  :focus=>8}, {:pm=>61, :scs=>23,  :focus=>8}],
[{:pm=>65, :scs=>20, :focus=>8}, {:pm=>65, :scs=>23,  :focus=>8}],
[{:pm=>59, :scs=>20, :focus=>1}, {:pm=>59, :scs=>23,  :focus=>1}], 
[{:pm=>60, :scs=>20,  :focus=>1}, {:pm=>60, :scs=>23,  :focus=>1}],
[{:pm=>70, :scs=>20,  :focus=>10}, {:pm=>70, :scs=>25,  :focus=>10}],
[{:pm=>85, :scs=>60,  :focus=>10}, {:pm=>85, :scs=>25,  :focus=>10}],
[{:pm=>72, :scs=>20,  :focus=>10}, {:pm=>72, :scs=>25,  :focus=>10}]]
 

В одном месте мне нужно показать приведенный выше список в определенном порядке,этот порядок создается на основе взаимодействия с пользователем, то есть «group_pm_list», и задается в виде хэша,за которым нужно следовать, чтобы упорядочить приведенный выше массив:

      group_pm_list={"8"=>[65,61],"1"=>[60,59],"10"=>[70,85,72]}
 

Здесь нам нужно переупорядочить «продукт» на основе «group_pm_list» (который представляет собой упорядоченный список продуктов на основе некоторой фильтрации).

Сначала мне нужно получить ключ 8(:фокус) со значениями » pm » 65, затем 61. Во-вторых, мне нужно получить ключ 1(:фокус) со значениями » pm » 60, затем 59. В-третьих, мне нужно получить ключ 10(:фокус), и в этой группе необходимо поддерживать тот же порядок.

Как я могу сгенерировать отсортированный список, как указано в приведенном выше порядке group_pm_list, чтобы получить результат в виде:

 product = [[{:pm=>65, :scs=>20, :focus=>8},  {:pm=>65, :scs=>23,  :focus=>8}],
           [{:pm=>61, :scs=>20, :focus=>8},{:pm=>61,:scs=>23,  :focus=>8}],
           [{:pm=>60, :scs=>20, :focus=>1},{:pm=>60, :scs=>23,  :focus=>1}],
           [{:pm=>59, :scs=>20,  :focus=>1}, {:pm=>59, :scs=>23,  :focus=>1}],
           [{:pm=>70, :scs=>20,  :focus=>10}, {:pm=>70, :scs=>25,  :focus=>10}],
           [{:pm=>85, :scs=>60,  :focus=>10}, {:pm=>85, :scs=>25,  :focus=>10}],
           [{:pm=>72, :scs=>20,  :focus=>10}, {:pm=>72, :scs=>25,  :focus=>10}]]
 

Пожалуйста, помогите.Спасибо

Комментарии:

1. Я не уверен, почему эти данные представляют собой массив массивов? Самое первое , что вы с ним делаете, — это вызов .flatten , который подразумевает, что предыдущая операция возвращает неправильно отформатированную структуру данных.

Ответ №1:

Это очень запутанный способ определения порядка сортировки:

 group_pm_list={"8"=>[65,61],"1"=>[60,59]}
 
  1. Почему ключи являются строками, а не числами? Я предполагаю, что вы на самом деле хотели указать цифры и будете предполагать это в остальной части этого ответа.
  2. Вы уверены, что это не просто «сортировать по :pm убыванию»?? Это значительно более сложный порядок сортировки…
  3. Не могли бы вы определить порядок сортировки с помощью более чистого объекта данных? В этом хэше нет никакого упоминания о :focus nor :pm , поэтому немного странно «волшебным образом» знать, что это значит.

Я также предположу, что вы сгладите массив в какой-то момент, прежде чем использовать этот ответ, поскольку нет смысла, чтобы ваши данные были массивом массивов. Возможно, просто позвоните product.flatten! наверх, если изменение переменной нормально?

 product = [{:pm=>61, :scs=>20, :bg=>"#a3ffff", :impact=>4, :focus=>8}, {:pm=>61, :scs=>23, :bg=>"#a3ffff", :impact=>nil, :focus=>8}, {:pm=>65, :scs=>20, :bg=>"#a3ffff", :impact=>nil, :focus=>8}, {:pm=>65, :scs=>23, :bg=>"#a3ffff", :impact=>nil, :focus=>8}, {:pm=>59, :scs=>20, :bg=>"#ffffd9", :impact=>nil, :focus=>1}, {:pm=>59, :scs=>23, :bg=>"#ffffd9", :impact=>4, :focus=>1}, {:pm=>60, :scs=>20, :bg=>"#ffffd9", :impact=>1, :focus=>1}, {:pm=>60, :scs=>23, :bg=>"#ffffd9", :impact=>1, :focus=>1}]

group_pm_list={8 => [65,61], 1 =>[60,59]}

focus_sort_order = group_pm_list.keys
pm_sort_order = group_pm_list.values.flatten

product.sort do |p1, p2|
  [
    focus_sort_order.index(p1[:focus]), 
    pm_sort_order.index(p1[:pm])
  ] <=>
  [
    focus_sort_order.index(p2[:focus]), 
    pm_sort_order.index(p2[:pm])
  ]
end
 

Комментарии:

1. Ошибка типа (без неявного преобразования символа в целое число) из focus_sort_order.index(p1[:фокус]),

2. @джисси, Правда? Я просто скопировал вставил код на свою машину снова, чтобы запустить его, и не увидел ошибки. Возможно, вы все еще используете массив массивов, не выравнивая его сначала, как я предупреждал.

3. Если вам интересно, как работает эта реализация, см.: rubydoc.info/stdlib/core/Array:sort и ruby-doc.org/core-2.7.0/Array.html#method-i-3C-3D-3E . Реализация, по общему признанию, довольно сложна для понимания, но это неизбежно, учитывая очень странную/пользовательскую логику, которую вы пытаетесь применить здесь.

Ответ №2:

 product = [
  [{:pm=>61, :scs=>20,  :focus=>8}, {:pm=>61, :scs=>23,  :focus=>8}],
  [{:pm=>65, :scs=>20, :focus=>8}, {:pm=>65, :scs=>23,  :focus=>8}],
  [{:pm=>59, :scs=>20, :focus=>1}, {:pm=>59, :scs=>23,  :focus=>1}], 
  [{:pm=>60, :scs=>20,  :focus=>1}, {:pm=>60, :scs=>23,  :focus=>1}],
  [{:pm=>70, :scs=>20,  :focus=>10}, {:pm=>70, :scs=>25,  :focus=>10}],
  [{:pm=>85, :scs=>60,  :focus=>10}, {:pm=>85, :scs=>25,  :focus=>10}],
  [{:pm=>72, :scs=>20,  :focus=>10}, {:pm=>72, :scs=>25,  :focus=>10}]
]

group_pm_list={"8"=>[65,61],"1"=>[60,59],"10"=>[70,85,72]}
 

Сол 1

 group_pm_list.flat_map do |k, v|
  v.flat_map do |m|
    product.select { |n|
      n[0][:pm] == m
    }
  end
end
 

Сол 2

 grouped_products = product.group_by {|elem| elem[0][:pm]}
group_pm_list.flat_map do |k, v|
  v.flat_map { |m| grouped_products[m] }
end
 

Сол 3

 grouped_products = product.group_by {|elem| elem[0][:pm]}
group_pm_list.flat_map do |k, v|
  v.map { |m| grouped_products[m][0] }
end
 

Комментарии:

1. Жесткое кодирование "8" не кажется разумным решением. Вы не можете предположить, что определенное число , например 8 , находится в порядке сортировки.

2. @TomLord, который может исходить из запроса, имеет вопрос, укажите, есть ли :focus номер, который будет там, поэтому я просто закодировал его

3. Хорошо, но это невозможно доказать никаким реальным решением в реальном мире. Вот почему я сказал, что это не совсем правильный ответ.