Вопрос:

Ruby group массив хэшей по числовому ключу

arrays ruby hash

224 просмотра

4 ответа

66 Репутация автора

Я получил массив хэшей, как этот:

[{1=>6}, {1=>5}, {4=>1}]

Я пытаюсь сгруппировать по ключам.

Таким образом, решение с именованными ключами было как: group_by { |h| h['keyName'] }.

Как я могу получить следующий массив с короткими лямбда-выражениями или с group_by:

[{1=>[5, 6], 4=>[1]}]

РЕДАКТИРОВАТЬ - Чтобы объяснить, что я пытаюсь достичь: у меня есть база данных для распределения учеников на курсы. Каждый ученик может каждый год голосовать за курс.

Голоса выглядят так:

Vote(id: integer, first: integer, second: integer, active: boolean,
     student_id: integer, course_id: integer, year_id: integer,
     created_at: datetime, updated_at: datetime)

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

Year.get_active_year.votes.order(:first).map(&:first).group_by(&:itself)

результат выглядит так:

{1=>[1, 1], 4=>[4]}

Теперь я могу использовать функцию .each:

Year.get_active_year.votes.order(:first).map(&:first).group_by(&:itself).each do |_key, value|
  if Year.get_active_year.courses.where(number: _key).first.max_visitor >= value.count

  end
end

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

Но если я сделаю все это, я потеряю информацию о том, какой ученик проголосовал за этот курс, поэтому я попытался сохранить такую ​​информацию:

Year.get_active_year.votes.order(:first).map{|c| {c.first=> c.student_id}}
Автор: homior Источник Размещён: 04.01.2018 09:05

Ответы (4)


2 плюса

109750 Репутация автора

def group_values(arr)
  arr.reduce(Hash.new {|h,k| h[k]=[]}) do |memo, h|
    h.each { |k, v| memo[k] << v }
    memo
  end
end

xs = [{1=>6}, {1=>5}, {4=>1}]
group_values(xs) # => {1=>[6, 5], 4=>[1]}

Обратите внимание, что это решение также работает, когда хэши содержат несколько записей:

ys = [{1=>6, 4=>2}, {1=>5}, {4=>1}]
group_values(ys) # => {1=>[6, 5], 4=>[2, 1]}
Автор: maerics Размещён: 04.01.2018 09:24

1 плюс

3629 Репутация автора

Один из способов добиться этого с использованием #group_byгруппирования по первому ключу каждого хэша, а затем #mapпо результату, чтобы получить соответствующие значения:

arr = [{1=>6}, {1=>5}, {4=>1}]
arr.group_by {|h| h.keys.first}.map {|k, v| {k => v.map {|h| h.values.first}}}

# => [{1=>[6, 5], 4=>[1]}]

Надеюсь это поможет!

Автор: Zoran Размещён: 04.01.2018 09:24

4 плюса

261 Репутация автора

Решение

Внедрение в хеш по умолчанию:

arr = [{1=>6}, {1=>5}, {4=>1}]
arr.inject(Hash.new{|h,k| h[k]=[]}){|h, e| h[e.first[0]] << e.first[1]; h}

# => {1=>[6, 5], 4=>[1]}

Или, как предлагается в комментариях:

arr.each.with_object(Hash.new{|h, k| h[k] = []}){|e, h| h[e.first[0]] << e.first[1]}

# => {1=>[6, 5], 4=>[1]}
Автор: Hallgeir Wilhelmsen Размещён: 04.01.2018 09:53

2 плюса

73763 Репутация автора

arr = [{1=>6}, {1=>5}, {4=>1}]

arr.flat_map(&:to_a).
    group_by(&:first).
    transform_values { |arr| arr.transpose.last }
  #=> {1=>[6, 5], 4=>[1]}

Шаги следующие.

a = arr.flat_map(&:to_a)
  #=> [[1, 6], [1, 5], [4, 1]]
b = a.group_by(&:first)
  #=> {1=>[[1, 6], [1, 5]], 4=>[[4, 1]]}
b.transform_values { |arr| arr.transpose.last }
  #=> {1=>[6, 5], 4=>[1]}

Обратите внимание, что

b.transform_values { |arr| arr.transpose }
  #=> {1=>[[1, 1], [6, 5]], 4=>[[4], [1]]}

и arr.flat_map(&:to_a)может быть заменен на arr.map(&:flatten).

По-другому:

arr.each_with_object({}) do |g,h|
  k,v = g.flatten
  h.update(k=>[v]) { |_,o,n| o+n }  
end
  #=> {1=>[6, 5], 4=>[1]}

При этом используется форма Hash # update (aka merge!), которая использует блок { |_,o,n| o+n }для определения значений ключей, которые присутствуют в обоих объединяемых хэшах. Переменная блока _- это общий ключ (представленный подчеркиванием для обозначения того, что он не используется в вычислениях блока). Переменные oи nявляются соответственно значениями общего ключа в двух объединяемых хешах.

Автор: Cary Swoveland Размещён: 05.01.2018 07:24
32x32