Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > count : array to array of hashes

Reply
Thread Tools

count : array to array of hashes

 
 
Jean-Sébastien
Guest
Posts: n/a
 
      08-01-2007
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,:cou nt=>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....a7b10da8195cec

If someone could help.

regards

 
Reply With Quote
 
 
 
 
Robert Dober
Guest
Posts: n/a
 
      08-01-2007
On 8/1/07, Jean-S=E9bastien <(E-Mail Removed)> wrote:
> Hi,
> I'm tryind to count distinct ids from an array (array_of_ids =3D
> [1,2,3,1,2]), and want a result array of hashes looking like it :
> result =3D [{;id=3D>1,:count=3D>2},{;id=3D>2,:count=3D>2},{;id =3D>3,:coun=

t=3D>1}]
>
> i tried it, but it always returns errors :
> result =3D array_of_ids.inject(Array.new){ |a,x| elt =3D a.find{|h| h[:id=

]
> =3D=3D x} || {:id =3D> x, :count =3D> 0}; elt[:count] +=3D 1; elt}
>
> i took my information from this post :
> http://groups.google.com/group/comp....thread/312221=

2f6db8d7f5/04a7b10da8195cec?lnk=3Dgst&q=3Darray++count&rnum=3 D8#04a7b10da81=
95cec
>
> If someone could help.
>
> regards
>
>
>

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

HTH
Robert



--=20
[...] as simple as possible, but no simpler.
-- Attributed to Albert Einstein

 
Reply With Quote
 
 
 
 
Stefano Crocco
Guest
Posts: n/a
 
      08-01-2007
Alle mercoled=EC 1 agosto 2007, Jean-S=E9bastien ha scritto:
> Hi,
> I'm tryind to count distinct ids from an array (array_of_ids =3D
> [1,2,3,1,2]), and want a result array of hashes looking like it :
> result =3D [{;id=3D>1,:count=3D>2},{;id=3D>2,:count=3D>2},{;id =3D>3,:coun=

t=3D>1}]
>
> i tried it, but it always returns errors :
> result =3D array_of_ids.inject(Array.new){ |a,x| elt =3D a.find{|h| h[:id]
> =3D=3D x} || {:id =3D> x, :count =3D> 0}; elt[:count] +=3D 1; elt}
>
> i took my information from this post :
> http://groups.google.com/group/comp....thread/312221=

2f
>6db8d7f5/04a7b10da8195cec?lnk=3Dgst&q=3Darray++count&rnum=3 D8#04a7b10da819=

5cec
>
> 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=
=20
worked) the hash containing the id which is being processed. You should=20
return a, that is the array which contains the hashes. Correcting this shou=
ld=20
give a piece of code which executes without errors, but which returns an=20
empty array
2- you never insert the hashes you create inside the inject block into the=
=20
array a: you only store them in the local variable elt, which gets destroye=
d=20
after each iteration. The inject block should be:

result =3D array_of_ids.inject(Array.new){ |a,x|=20
elt =3D ( a.find{|h| h[:id] =3D=3D x} || a[a.size] =3D {:id =3D> x, :co=
unt =3D> 0} )
elt[:count] +=3D 1
a
}

As you can see, after the || operator a new hash is created and inserted at=
=20
the end of a (corresponding to the index a.size). Since an assignment alway=
s=20
return the value being assigned (this is why I didn't use <<, it returns th=
e=20
array, not the inserted element), elt is then set to the new hash. Of cours=
e,=20
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=20
resulting array contains the hashes in the same order as the id are stored =
in=20
the array, here's another approach you can consider:

result =3D array_of_ids.inject([]) do |res, i|
res[i-1] ||=3D {:id =3D> i, :count =3D> 0}
res[i-1][:count] +=3D 1
res
end

This code stores the data relative to the id i in the i-1 position in the=20
array (the -1 is there to avoid a nil element at the beginning). This shoul=
d=20
make it faster, since you don't need to iterate all the array to check=20
whether the data corresponding to an id is already there or not: either is =
in=20
the position id - 1 or it itsn't there. A quick benchmark, done by creating=
=20
an array of ids of 100_000 elements, with values randomly chosen between 1=
=20
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.73356

The original approach takes much more time (I didn't have the patience to w=
ait=20
for it to complete).

I hope this helps

Stefano


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Array of Hashes in an array of hashes - Complicated! Matt Brooks Ruby 16 09-16-2009 05:53 PM
How to make an array of hashes to a single array with all thevalues of these hashes ? kazaam Ruby 12 09-13-2007 01:30 PM
using hashes as keys in hashes Steven Arnold Ruby 3 11-23-2005 03:25 PM
Hash of hashes, of hashes, of arrays of hashes Tim O'Donovan Perl Misc 5 10-28-2005 05:59 AM
Hashes of Hashes via subs Ben Holness Perl 8 10-08-2003 06:57 AM



Advertisments