2013-08-19 2 views
0

Преобразование следующего хэша в другой хеш.Преобразование одного хэша в другой хэш в рубине

{["2013-08-15", "123", "user1"]=>1, ["2013-08-15", "456", "user1"]=>1, ["2013-08-09", "789", "user1"]=>5} 

Преобразование выше хэш

{["2013-08-15", "user1"]=>2, ["2013-08-09", "user1"]=>1} 

Как вы можете увидеть первый и второй ключ, значение пары в хэш имеют ту же дату, другой учетной записи, и тот же пользователь, в данном случае я нужно подсчитать общее количество постов пользователей, как два {["2013-08-15", "user1"]=>2}

в последнем ключе, значение пара, счетчик должен быть один, потому что пользователь отправил на только один счет («789»), даже если есть 5 сообщений {["2013-08-09", "user1"]=>1}.

+0

@mbratch Конечно, вы можете. IIRC любой объект может быть использован как хэш-ключ, если он отвечает на 'hash' и' eql? '. –

+0

@mbratch Конечно, вы можете. '{[1] => 'foo'} [[1]]' возвращает 'foo'. –

ответ

2
h = {["2013-08-15", "123", "user1"]=>1, ["2013-08-15", "456", "user1"]=>1, ["2013-08-09", "789","user1"]=>5} 
Hash[h.group_by{|k,v| k[0]}.map{|_,v| [v.flatten.values_at(0,2),v.size]}] 
# => {["2013-08-15", "user1"]=>2, ["2013-08-09", "user1"]=>1} 

Или

h = {["2013-08-15", "123", "user1"]=>1, ["2013-08-15", "456", "user1"]=>1, ["2013-08-09", "789","user1"]=>5} 
h.each_with_object(Hash.new(0)){|((d,_,u),_),hsh| hsh[[d,u]] +=1 } 
# => {["2013-08-15", "user1"]=>2, ["2013-08-09", "user1"]=>1} 
+0

Он работал отлично. – Kumar

2

Не очень элегантный, но работает. Кроме того, использование массивов в качестве хеш-ключей довольно странно.

h = {["2013-08-15", "123", "user1"]=>1, ["2013-08-15", "456", "user1"]=>1, ["2013-08-09", "789", "user1"]=>5} 
h.inject(Hash.new(0)){|a,((date,post,user),v)| a[[date,user]] +=1; a } # => {["2013-08-15", "user1"]=>2, ["2013-08-09", "user1"]=>1} 
+0

Спасибо, Абэ. Это сработало. – Kumar

1
hash1 = {["2013-08-15", "123", "user1"]=>1, ["2013-08-15", "456", "user1"]=>1, ["2013-08-09", "789", "user1"]=>5} 

    hash2 = Hash.new 
    hash1.each do |x,y| 
     hash2[ [x[0],x[2]] ] = hash2[ [x[0],x[2]] ].to_i + 1 
    end 
    puts hash2 

Обратите внимание, что вам нужно использовать .to_i метод для инициализации первого времени, в противном случае мы будем добавлять с ноль, но это делает его 0.

3

Использование Facets 'Enumerable#frequency вы может написать эту чистую и модульную Однострочник:

require 'facets' 
hash1 = {["2013-08-15", "123", "user1"] => 1, ...} 
hash2 = hash1.keys.map { |date, code, user| [date, user] }.frequency 
#=> {["2013-08-15", "user1"] => 2, ["2013-08-09", "user1"] => 1} 

Обратите внимание, что распаковывать значение массива делает легче увидеть, что происходит. Также обратите внимание, что вам не нужно зависеть от Facets, просто добавьте Enumerable#frequency в свою библиотеку расширений, это очень распространенная абстракция.

+0

Я получил эту ошибку hash1.keys.map {| дата, код, пользователь | [date, user]} .frequency NoMethodError: неопределенный метод 'frequency 'для # Kumar

+1

ну, конечно, вам нужно установить грани:' gem install facets'. – tokland

1

Это может быть сделано с group_by и map:

h = {["2013-08-15", "123", "user1"]=>1, ["2013-08-15", "456", "user1"]=>1, ["2013-08-09", "789", "user1"]=>5} 

Hash[h.group_by { |(u, _, d), _| [u, d] }.map { |u, d| [u, d.size] }] 
#=> {["2013-08-15", "user1"]=>2, ["2013-08-09", "user1"]=>1} 
+0

+1. Обратите внимание: насколько мне нравится FP, где использование '_' означает« что угодно »- это общая идиома, я предпочитаю давать имена неиспользуемым переменным, это более понятно. В Ruby, по крайней мере, это выглядит странно. – tokland

Смежные вопросы