Topic: Extending Array

Hi,

i would like to select every n-th object from an array and i found this code on the snippets site, which would be great to have:

class Array
  def every(n)
    select {|x| index(x) % n == 0}
  end
  def every_other
    every 2
  end
end

Example:

[1, 2, 3, 4].every_other
=> [1, 3]


Where do i have to put this to access it whenever needed?

If there is a better solution, please let me know also smile
Even better, is it possible to select every n-th record from the database smile ?

Thanks!

Re: Extending Array

Interesting. I'm not sure you could do this for a DB call unless you did some tricky work before hand like a Model.find(:all, where id is in ?, [x]). Where [x] is an array of numbers you've called every(#) on and you would also have to know some maximal value of items in your DB, say 1,000 or 10,000.

As for your first question I'm pretty sure you would put this in your config/environment.rb file. Sorry I can't tell you exactly how to do it but here are two examples from one of my environment files of how I extended a base class

Time::DATE_FORMATS[:m_d_y] = "%m/%d/%y"
OR
ActionMailer::Base.perform_deliveries = true

So something like this is what you'll need. Use Google and the Rails API to figure it out. (just an FYI: I think it's called "monkey patching")

Array::Base.every {
code here
}

Also your example is wrong every_other would return [2,4] If you want every n-th starting with the first one I think the code would be:

select {|x| index(x) % n == 1}

Last edited by JackVandaL (2009-01-08 17:24:14)

Re: Extending Array

In my apps I create a new folder called 'patches' in the 'lib' folder. So in your example I'd then put a file called 'array.rb' in my RAILS_ROOT/lib/patches folder, it'd contain this:

class Array
  def every(n)
    select {|x| index(x) % n == 0}
  end
  def every_other
    every 2
  end
end

I then use an initializer to load my patch files when Rails starts, in RAILS_ROOT/config/initializers I create a file called 'a.rb' that contains this:

Dir[File.join(Rails.root, 'lib', 'patches', '**', '*.rb')].sort.each { |patch| require(patch) }

I call the file 'a.rb' because Rails loads initializers in alphabetical order and I want to make sure my monkey-patches are loaded first smile The initializer code just loads any files that are in the RAILS_ROOT/lib/patches folder (so any future patches you put in there will be loaded automatically).

A couple of things to note: you will need to restart your server if you make any changes to files in the lib/patches folder, and if your version of Rails doesn't support initializers then the code from 'a.rb' could go in environment.rb instead.

Rob Anderton
TheWebFellas

Re: Extending Array

I'd probably do something like this:

class Array
  def every( n )
    return [] if self.empty?
    return [ self.first ] if self.size < n
    [ self.first ] + self[ n, self.size ].every( n )
  end
end

Last edited by Ninju (2009-01-28 12:22:20)

If I've helped you out with something, feel free to recommend me on working with rails.