Простейшим подходом будет использование group_by
:
Input.cart.line_items.group_by { |item| item.variant.product.product_type }
Это должно возвращать хеш точно так, как нужно - вывод оцененного блока возвращается как ключ хеша (т. Е. item.variant.product.product_type
), с элементами, назначенными в качестве массива значений для этих ключей.
Примечание: если вы запрашиваете несколько записей, связанных с line_item
, стоит including
, чтобы избежать проблем с N + 1, например.
Input.cart.line_items.includes(variant: { product: :product_type }).group_by do |item|
item.variant.product.product_type
end
Вот еще один простой способ добиться того, чего вы добились после использования each_with_object
:
Input.cart.line_items.each_with_object(Hash.new { |h, k| h[k] = [] }) do |item, hash|
hash[item.variant.product.product_type] << item
end
Редактировать: только что понял, что ваш вопрос помечен как Ruby, а не Rails. В этом случае each_with_object
недоступен, хотя вы можете добиться аналогичного результата, используя reduce
:
Input.cart.line_items.reduce(Hash.new { |h, k| h[k] = [] }) do |hash, item|
hash.tap { |h| h[item.variant.product.product_type] << item }
end
Обратите внимание на использование tap
: reduce
возвращает все, что оценивает блок, а не объект и присваивает первому аргументу блока (в данном случае hash
). Использование tap
гарантирует, что это всегда хеш.
С точки зрения того, что является «правильным», group_by
существует именно для этой цели - использование этого даст читабельный подход, оптимизированный для выполняемой задачи.
Надеюсь, это поможет - дайте мне знать, как вы поживаете, и если у вас есть какие-либо вопросы:)