# Count : array to array of hashes

**URL:** <https://www.ruby-forum.com/t/count-array-to-array-of-hashes/110982>\
**Category:** Ruby\
**Created:** [August 1, 2007, 6:05pm UTC](https://www.ruby-forum.com/t/count-array-to-array-of-hashes/110982 "2007-08-01T18:05:49Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![jney](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/49beb7/32.png) [@jney](https://www.ruby-forum.com/u/jney)\
**Post date:** [August 1, 2007, 6:05pm UTC](https://www.ruby-forum.com/t/count-array-to-array-of-hashes/110982/1 "2007-08-01T18:05:49Z")

</div>

Hi,  
I’m tryind to count distinct ids from an array (array\_of\_ids =  
[1,2,3,1,2]), and want a result array of hashes looking like it :  
result = [{;id=\>1,:count=\>2},{;id=\>2,:count=\>2},{;id=\>3,:count=\>1}]

i tried it, but it always returns errors :  
result = array\_of\_ids.inject(Array.new){ |a,x| elt = a.find{|h| h[:id]  
== x} || {:id =\> x, :count =\> 0}; elt[:count] += 1; elt}

i took my information from this post :  
[http://groups.google.com/group/comp.lang.ruby/browse\_thread/thread/3122212f6db8d7f5/04a7b10da8195cec?lnk=gst&q=array++count&rnum=8#04a7b10da8195cec](http://groups.google.com/group/comp.lang.ruby/browse_thread/thread/3122212f6db8d7f5/04a7b10da8195cec?lnk=gst&q=array++count&rnum=8#04a7b10da8195cec)

If someone could help.

regards

---

<div class="post-metadata">

**Author:** ![jney](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/49beb7/32.png) [@jney](https://www.ruby-forum.com/u/jney)\
**Post date:** [August 1, 2007, 6:34pm UTC](https://www.ruby-forum.com/t/count-array-to-array-of-hashes/110982/2 "2007-08-01T18:34:53Z")

</div>

On 8/1/07, Jean-Sébastien [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> [http://groups.google.com/group/comp.lang.ruby/browse\_thread/thread/3122212f6db8d7f5/04a7b10da8195cec?lnk=gst&q=array++count&rnum=8#04a7b10da8195cec](http://groups.google.com/group/comp.lang.ruby/browse_thread/thread/3122212f6db8d7f5/04a7b10da8195cec?lnk=gst&q=array++count&rnum=8#04a7b10da8195cec)
> 
> If someone could help.
> 
> regards

irb(main):005:0\> a=[1,2,3,42,2,2,3]  
=\> [1, 2, 3, 42, 2, 2, 3]  
irb(main):006:0\> a.inject([]){|r,ele| r[ele][:count]+=1 rescue  
r[ele]={:id =\> ele, :count=\>1}; r}.compact  
=\> [{:count=\>1, :id=\>1}, {:count=\>3, :id=\>2}, {:count=\>2, :id=\>3},  
{:count=\>1, :id=\>42}]  
irb(main):007:0\>

HTH  
Robert

---

<div class="post-metadata">

**Author:** ![jney](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/49beb7/32.png) [@jney](https://www.ruby-forum.com/u/jney)\
**Post date:** [August 1, 2007, 6:56pm UTC](https://www.ruby-forum.com/t/count-array-to-array-of-hashes/110982/3 "2007-08-01T18:56:54Z")

</div>

Alle mercoledì 1 agosto 2007, Jean-Sébastien ha scritto:

> [http://groups.google.com/group/comp.lang.ruby/browse\_thread/thread/3122212f](http://groups.google.com/group/comp.lang.ruby/browse_thread/thread/3122212f)  
> 6db8d7f5/04a7b10da8195cec?lnk=gst&q=array++count&rnum=8#04a7b10da8195cec
> 
> If someone could help.
> 
> regards

There are two problems in your code:  
1- in the inject block, you return elt, which is (or should be, if the  
code  
worked) the hash containing the id which is being processed. You should  
return a, that is the array which contains the hashes. Correcting this  
should  
give a piece of code which executes without errors, but which returns an  
empty array  
2- you never insert the hashes you create inside the inject block into  
the  
array a: you only store them in the local variable elt, which gets  
destroyed  
after each iteration. The inject block should be:

result = array\_of\_ids.inject(Array.new){ |a,x|  
elt = ( a.find{|h| h[:id] == x} || a[a.size] = {:id =\> x, :count =\>  
0} )  
elt[:count] += 1  
a  
}

As you can see, after the || operator a new hash is created and inserted  
at  
the end of a (corresponding to the index a.size). Since an assignment  
always  
return the value being assigned (this is why I didn’t use \<\<, it returns  
the  
array, not the inserted element), elt is then set to the new hash. Of  
course,  
all this happens only if find returns nil.

If you can rely in the id to be positive integers, and don’t care if the  
resulting array contains the hashes in the same order as the id are  
stored in  
the array, here’s another approach you can consider:

result = array\_of\_ids.inject([]) do |res, i|  
res[i-1] ||= {:id =\> i, :count =\> 0}  
res[i-1][:count] += 1  
res  
end

This code stores the data relative to the id i in the i-1 position in  
the  
array (the -1 is there to avoid a nil element at the beginning). This  
should  
make it faster, since you don’t need to iterate all the array to check  
whether the data corresponding to an id is already there or not: either  
is in  
the position id - 1 or it itsn’t there. A quick benchmark, done by  
creating  
an array of ids of 100\_000 elements, with values randomly chosen between  
1  
and 11 gives:

```
                          user system total real

```

original approach 5.730000 1.490000 7.220000 ( 7.310224)  
user system total real  
alternative approach 1.250000 0.150000 1.400000 ( 1.416871)

Changing the range of the ids from 11 to 101 gives:  
user system total real  
alternative approach 1.270000 0.190000 1.460000 ( 1.472353)  
user system total real  
original approach 37.730000 11.360000 49.090000 ( 51.056527)

Increasing it to 1001 gives  
user system total real  
alternative approach 1.500000 0.220000 1.720000 ( 1.733568)

The original approach takes much more time (I didn’t have the patience  
to wait  
for it to complete).

I hope this helps

Stefano
