Forum: Ruby creating an array by reusing code

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Sijo k. (Guest)
on 2009-03-25 12:45
Hi
   I have
all_req = OnRequest.find(:all, :conditions => [status_id = ?',6])

   Now i need to create an array of size 12 containing record counts for
month January to December like [recordcountjanuary,recordcountfeb,....]
So for the first month january I tried like

all_req.select do |r|
 r.created_at.mon == 1
end
       What i need is reuse the above code I have placed it in a
function But there I have to call it 12 times .How can i avoid this?

Thanks in advance
Sijo
Jesús Gabriel y Galán (Guest)
on 2009-03-25 13:09
(Received via mailing list)
On Wed, Mar 25, 2009 at 11:42 AM, Sijo Kg <removed_email_address@domain.invalid> 
wrote:
> end
>       What i need is reuse the above code I have placed it in a
> function But there I have to call it 12 times .How can i avoid this?

Maybe this helps (untested):

recordcount = (1..12).map do |month|
   all_req.select {|r| r.created_at.mon == month}.size
end

Although this does 12 passes through all_req. BTW, if you need the
count you need to check the size of the select. Maybe another approach
could be using a hash:

recordcount = Hash.new(0)
all_req.each do |r|
   recordcount[r.created_at.mon] += 1
end

Hope this helps,

Jesus.
lasitha (Guest)
on 2009-03-25 13:20
(Received via mailing list)
On Wed, Mar 25, 2009 at 4:12 PM, Sijo Kg <removed_email_address@domain.invalid> 
wrote:
> [...]
>   Now i need to create an array of size 12 containing record counts for
> month January to December like [recordcountjanuary,recordcountfeb,....]
> So for the first month january I tried like
>
> all_req.select do |r|
>  r.created_at.mon == 1
> end
>       What i need is reuse the above code I have placed it in a
> function But there I have to call it 12 times .How can i avoid this?

Let's build this up a step at a time...

monthly_counts = (1..12).map do |month|
  # call your function here, passing in the month
end

Depending on the scope of all_req, it may just be easier to inline the
function as follows:

monthly_counts = (1..12).map do |month|
  all_req.select {|r| r.created_at.mon == month }.size
end

However, this is inefficient.  We have to make 12 passes over the
all_req collection.
You can, instead use Enumerable#group_by:

all_req.group_by {|r| r.created_at.mon }

which will return a hash of items keyed by the month.  Getting counts
from this is simply a matter of using #map.  I'll leave this as an
exercise :)

Now, having said all that, the most efficient way to do this is
probably to use a group_by clause in your finder.  Again, left as an
exercise (mostly 'cos i don't know AR :)

solidarity,
lasitha
Robert K. (Guest)
on 2009-03-25 18:50
(Received via mailing list)
2009/3/25 lasitha <removed_email_address@domain.invalid>:

> However, this is inefficient.  We have to make 12 passes over the
> all_req collection.
> You can, instead use Enumerable#group_by:
>
> all_req.group_by {|r| r.created_at.mon }
>
> which will return a hash of items keyed by the month.  Getting counts
> from this is simply a matter of using #map.  I'll leave this as an
> exercise :)

Or create a counter Hash and loop once:

counts = Hash.new 0
all_req.each {|r| counts[r.created_at.mon] += 1}

> Now, having said all that, the most efficient way to do this is
> probably to use a group_by clause in your finder.  Again, left as an
> exercise (mostly 'cos i don't know AR :)

Yep, the database solution is probably the best.

Cheers

robert
This topic is locked and can not be replied to.