Couting of array according to hash key in Ruby

97 views Asked by At

I have an array

data = [{:user=>1399, :job=>10270}, {:user=>2614, :job=>10270},
        {:user=>3112, :job=>10270}, {:user=>2614, :job=>10271},
        {:user=>1455, :job=>10271}]

Where 1399, 2614, 3112, 1455 are user ids and 10270, 10271 are job ids.

I want to show the number of jobs per user regardless of the job id.

Expected result:

1399 => 1
2614 => 2 # because 2614 has 2 two jobs
3112 => 1
1455 => 1

i need this in an array

3

There are 3 answers

1
mrzasa On BEST ANSWER

First group_by the user key and then count the number of elements in each group:

IMPROVED SOLUTION

data = [{:user=>1399, :job=>10270}, {:user=>2614, :job=>10270}, {:user=>3112, :job=>10270}, {:user=>2614, :job=>10271}, {:user=>1455, :job=>10271}]
data.group_by {|e| e[:user]}
  .transform_values(&:size)
# => {1399=>1, 2614=>2, 3112=>1, 1455=>1}

ORIGINAL SOLUTION

data = [{:user=>1399, :job=>10270}, {:user=>2614, :job=>10270}, {:user=>3112, :job=>10270}, {:user=>2614, :job=>10271}, {:user=>1455, :job=>10271}]
data.group_by {|e| e[:user]}
  .map{|id, a| [id, a.size]}
  .to_h
# => {1399=>1, 2614=>2, 3112=>1, 1455=>1}
3
Stefan On

You can extract the user ids via map and then let Ruby count the occurrences via tally:

data.map { |h| h[:user] } #=> [1399, 2614, 3112, 2614, 1455]
    .tally                #=> {1399=>1, 2614=>2, 3112=>1, 1455=>1}
0
Cary Swoveland On

My answer is to round-out what I believe are the standard ways of doing this.

data.each_with_object(Hash.new(0)) { |g,h| h[g[:user]] += 1 }
  #=> {1399=>1, 2614=>2, 3112=>1, 1455=>1}

It works with older versions of Ruby and avoids the construction of a temporary array or hash.

See the form of Hash::new that takes an argument and no block. If a hash is defined h = Hash.new(0) then later, if (and only if) h has no key k, h[k] = 0 is executed before h[k] += 0. h is sometimes called a counting hash.