Как обращаться к ключам вложенного массива после группировки в Rails? - PullRequest
2 голосов
/ 01 ноября 2019

У меня есть таблица, называемая продажами, подобная этой:

id    customer_id    product_id    sales
1        4           190            100
2        4           190            150
3        4           191            200
4        5           192            300
5        6           200            400

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

Sales.all.group(:customer_id, product_id).sum(:sales)

. Это дает мне хеш с ключами, состоящими из массивов с комбинацией customer_id и product_id:

hash = {
  [4, 190] => 250,
  [4, 191] => 200,
  [5, 192] => 300,
  [6, 200] => 400
}

Хотя это дает мнеВ результате я теперь также рассчитываю получить общую сумму продаж для каждого покупателя. Я мог бы, конечно, написать еще один запрос, но это кажется излишним. Разве нет простого способа найти все ключи хеш-массива, начинающиеся с [4, *] или чего-то еще?

Ответы [ 5 ]

2 голосов
/ 01 ноября 2019

Чтобы получить это значение для одного значения, вы можете сделать следующее:

hash.select{|x| x[0] == 4}.values.sum 
=> 450

Но вы также можете преобразовать хэш в сгруппированный в идентификаторах клиентов.

hash.inject(Hash.new(0)) do |result, v| 
  # v will look like [[4, 190], 250]
  customer_id = v[0][0] 
  result[customer_id] += v[1]
  result
end 

, который вы также можете написать в виде однострочника

hash.inject(Hash.new(0)){|result, v| result[v[0][0]] += v[1]; result} 
=> {4=>450, 5=>700}

, который может быть дополнительно сокращен при использовании each_with_object вместо inject (благодаря комментатору Себастьяну Пальме)

hash.each_with_object(Hash.new(0)){|v,result| result[v[0][0]] += v[1]}
1 голос
/ 01 ноября 2019

Вы можете попробовать следующее,

hash.group_by { |k,v| k.first }.transform_values { |v| v.map(&:last).sum }
# => {4=>450, 5=>300, 6=>400} 
1 голос
/ 01 ноября 2019

Вы можете сгруппировать полученный хеш на основе идентификатора клиента. Затем суммируйте все значения в группе:

hash = {
  [4, 190] => 250,
  [4, 191] => 200,
  [5, 192] => 300,
  [6, 200] => 400
}

hash.group_by { |entry| entry.shift.first }
    .transform_values { |sums| sums.flatten.sum }
#=> {4=>450, 5=>300, 6=>400}

group_by группирует пары ключ-значение на основе идентификатора клиента. shift удалит ключ (оставив только значения), а first выберет идентификатор клиента (так как это первый элемент в массиве). Это оставляет вам хеш { 4 => [[250], [200]], 5 => [[300]], 6 => [[400]] }.

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

1 голос
/ 01 ноября 2019

Попробуйте это:

hash.each_with_object(Hash.new(0)) do |(ids, value), result|
  result[ids.first] += value
end
#=> { 4 => 450, 5 => 700 }
0 голосов
/ 01 ноября 2019

Другой подход - группировать по идентификатору.

hash.
  group_by { |(k, _), _| k }.
  each_with_object(Hash.new{0}) do |(k, arr), acc|
    acc[k] += arr.sum(&:last)
end

#⇒ {4=>450, 5=>700}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...