On 01.11.2008 07:11, Jason Leong wrote:
> Dear all,
> 
> My application uses a calendar which I'm populating using an array of
> indexed RollingEvent objects. A RollingEvent is one of a series,
> multiplied from its original Event's repeat options (daily, weekly,
> fortnightly etc). The idea is that when a user saves an Event, the app
> uses a loop to generate and store all the RollingEvents for the coming
> year.
> 
> So a new Event is added, add_rolling_event is called within the loop
> (I've omitted most of the params for readability):
> 
>  def add_rolling_event(id, title, calendar_date)
>     @events[calendar_date.to_date] ||= []
>     @events[calendar_date.to_date] << RollingEvent.new(id, title,
> calendar_date)
>  end

You can make that a tad more efficient by doing

def add_rolling_event(id, title, calendar_date)
   (@events[calendar_date.to_date] ||= []) <<
     RollingEvent.new(id, title, calendar_date)
end

> The indexing works well, as in the calendar view I can quickly pull out
> the RollingEvent objects for that specific day. For the moment, whenever
> an Event is edited the entire @events array is reset and a routine loops
> through all Events to re-generate RollingEvents.
> 
> I'm trying to speed up the process by just deleting the RollingEvents
> pertinent to the Event that's being edited, then calling
> add_rolling_event for the Event in question.
> 
> I have 3 questions:
> 
> 1. Is using an indexed array actually faster than picking out events on
> the day using @events.select { |e| e.calendar_date == date }? It would
> be good to uncomplicate this if possible.

What do you mean by "indexed array"?  I am not sure what your #to_date 
returns so you might be using a Hash or an Array.  Ultimately when it 
comes to "faster" you need to implement different variants and benchmark 
them.  Fortunately this is pretty easily done in Ruby.

> 2. It seems that if I were to use delete_if on an indexed array, I'd
> have to loop through the array of RollingEvent objects for each indexed
> day. Am I right in assuming that this is uber-inefficient? Is there a
> better way to do this?

Well, it seems you have to access paths to an event: lookup by date and 
lookup by event id.  I do not know whether there are other access paths 
(e.g. search for event name or such) but assuming for the moment that 
there are just the two a solution with two Hashes seems most appropriate

class Calendar
   def initialize
     @ev_by_date = Hash.new {|h,k| h[k] = []}
     @ev_by_id = Hash.new {|h,k| h[k] = []}
   end

   def add_rolling_event(id, title, calendar_date)
     ev = RollingEvent.new(id, title, calendar_date)
     @ev_by_date[calendar_date] = ev
     @ev_by_id[id] = ev
   end

   def delete_by_id(id)
     @ev_by_id.delete(id).each do |ev|
       @ev_by_date[ev.date].delete(ev)
     end
   end

   def delete_by_date(date)
     @ev_by_date.delete(date).each do |ev|
       @ev_by_id[ev.id].delete(ev)
     end
   end
end

> 3. Currently @events (in a model called Event_Roster) and RollingEvents
> are all non-database-backed for performance, and stored in a memcached
> session. My concern has always been that - hypothetically - one could
> have 10 daily Events, resulting in 3650 RollingEvents. This doesn't seem
> to be a scalable solution, and the read/writes to and from the database
> would be costly. Would you advise writing all RollingEvents to a
> database, and is the performance hit negligable?

There are a lot other factors that you need to consider when thinking 
about the database.  3600 events is certainly a small number, even when 
read from a flat file.  You rather want a DB if your application needs 
to run on multiple machines concurrently and you want to have a single 
repository etc.  As long as you can foresee that there will not be 
millions of entries I would probably not complicate the application by 
adding another component.

Kind regards

	robert