1

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

Stefan
  • 109,145
  • 14
  • 143
  • 218

3 Answers3

3

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}
Stefan
  • 109,145
  • 14
  • 143
  • 218
  • It show undefined method 'tally' may be reason is i am new to ruby. But this works 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 – Mohammad Yusuf Jun 17 '22 at 09:50
  • @MohammadYusuf seems like you're using an older version of Ruby. `Enumerable#tally` was introduced in Ruby 2.7. – Stefan Jun 17 '22 at 09:51
  • Thatswhy, i am using 2.4. Thanks to you – Mohammad Yusuf Jun 17 '22 at 09:52
2

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}
mrzasa
  • 22,895
  • 11
  • 56
  • 94
0

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.

Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100