2014-11-14 2 views
0

У меня есть Рубин массив:Рубин массив ключ group_by с несколькими значениями

[ 
    {tags: [1,2]}, 
    {tags: [1,3]}, 
    {tags: [1,4]}, 
    {tags: [2,4]}, 
    {tags: [2,5]} 
] 

Мне нужно сгруппировать объекты по тэгам:

{ 
    1: [{tags: [1,2]}, {tags: [1,3]}, {tags: [1,4]}], 
    2: [{tags: [1,2]}, {tags: [2,4]}, {tags: [2,5]}], 
    3: [{tags: [1,3]}], 
    4: [{tags: [1,4]}, {tags: [2,4]}], 
    5: [{tags: [2,5]}] 
} 

Есть волшебный рубин способ сделать это?

+1

Есть вопрос где-то там? С чем конкретно вы столкнулись? –

+1

@MarkThomas Вопрос в названии. Учитывая массив Ruby Arash из хэш-элементов, я хочу индексировать эти элементы по значениям в свойстве Array каждого хэша. Труднее описать словами, чем показать вам код. Отсюда мой краткий вопрос с акцентом на код. – colllin

+0

@MarkThomas, этот вопрос сродни: «какое следующее число в последовательности 3, 9, 18, 30, 45?» Я не мог понять этот вопрос, пока не прочитал ответы. Похоже, что если 'i' удовлетворяет' h [: tags] .include? [I] => true' для хотя бы одной из пяти хэшей 'h', то' i' является ключом в возвращаемом хэше, а его value - массив всех хэшей 'h', для которых' h [: tags] .include? [i] => true'. (Следующий элемент в последовательности обозначается буквой '3 (n + n^2)/2'.) –

ответ

4

Использование Enumerable#each_with_object:

tags = [ 
    {tags: [1,2]}, 
    {tags: [1,3]}, 
    {tags: [1,4]}, 
    {tags: [2,4]}, 
    {tags: [2,5]} 
] 
tags.each_with_object(Hash.new { |h,k| h[k] = [] }) { |h, result| 
    h[:tags].each { |n| result[n] << h } 
} 
# => {1=>[{:tags=>[1, 2]}, {:tags=>[1, 3]}, {:tags=>[1, 4]}], 
#  2=>[{:tags=>[1, 2]}, {:tags=>[2, 4]}, {:tags=>[2, 5]}], 
#  3=>[{:tags=>[1, 3]}], 
#  4=>[{:tags=>[1, 4]}, {:tags=>[2, 4]}], 
#  5=>[{:tags=>[2, 5]}]} 
+0

Хороший ответ и прелесть для выяснения того, что было задано. –

2

Я хотел бы сделать что-то вроде этого:

array = [{tags: [1,2]}, {tags: [1,3]}, {tags: [1,4]}, {tags: [2,4]}, {tags: [2,5]}] 

result = Hash.new { |hash, key| hash[key] = [] } 

array.each do |tags| 
    tags[:tags].each { |tag| result[tag] << tags } 
end 

puts result 
#=> {1=>[{:tags=>[1, 2]}, {:tags=>[1, 3]}, {:tags=>[1, 4]}], 
# 2=>[{:tags=>[1, 2]}, {:tags=>[2, 4]}, {:tags=>[2, 5]}], 
# 3=>[{:tags=>[1, 3]}], 
# 4=>[{:tags=>[1, 4]}, {:tags=>[2, 4]}], 
# 5=>[{:tags=>[2, 5]}]} 
+0

Спасибо @spickermann. Это похоже на то, что я придумал сам по себе, но ваш переход к блоку «Hash.new» - это элегантное прикосновение. – colllin

+0

Вы, должно быть, тоже разобрались в вопросе, учитывая, что ваш ответ следовал так близко по пятам от фальстру. +1 для этого один, но хороший ответ тоже. –

1

я предлагаю следующее:

tags.each_with_object({}) {|g,h| g.values.flatten.each {|i| (h[i]||=[]) << g}} 
    #=> {1=>[{:tags=>[1, 2]}, {:tags=>[1, 3]}, {:tags=>[1, 4]}], 
    # 2=>[{:tags=>[1, 2]}, {:tags=>[2, 4]}, {:tags=>[2, 5]}], 
    # 3=>[{:tags=>[1, 3]}], 
    # 4=>[{:tags=>[1, 4]}, {:tags=>[2, 4]}], 
    # 5=>[{:tags=>[2, 5]}]} 
Смежные вопросы