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