Finding Matches in Array of Classes

R

Rob Redmon

I have an ActiveRecord find result. An element's contents look like:

irb(main):090:0> results[0]
=> #<InventoryHour id: 47475, observation_time: "2008-01-01 00:00:00",
station_id: 6, extension_id: 22, disk: 4, archive: 0, updated_on:
"2009-04-15 15:57:16">

The class of "observation_time" is:
results[0].observation_time.class
=> Time


What I'd like to do is find those elements which match on a particular
range of "observation_time". I'm used to Matlab and IDL programming
where one just does something like this:

indices = where( results.observation_time >= "2008-1-1" and
results.observation_time < "2009-1-1" )

What's the ruby way? Obviously, I can't use Array.include? but
something like that would be nice.

Rob
 
7

7stud --

Rob said:
What's the ruby way?

now = Time.now
in_a_minute = now + 60
in_two_minutes = now + 2*60

if in_a_minute.between?(now, in_two_minutes)
puts 'yes1'
end

if in_a_minute.between?(in_a_minute, in_two_minutes)
puts 'yes2'
end

if in_a_minute.between?(now, in_a_minute)
puts 'yes3'
end

if now.between?(in_a_minute, in_two_minutes)
puts 'yes4'
end

--output:--
yes1
yes2
yes3
 
7

7stud --

7stud said:
if in_a_minute.between?(now, in_two_minutes)
puts 'yes1'
end

I just thought I'd mention that Time mixes in Comparable, which is where
it gets the between? method from.
 
S

snex

I have an ActiveRecord find result.  An element's contents look like:
irb(main):090:0> results[0]
=> #<InventoryHour id: 47475, observation_time: "2008-01-01 00:00:00",
station_id: 6, extension_id: 22, disk: 4, archive: 0, updated_on:
"2009-04-15 15:57:16">
The class of "observation_time" is:
results[0].observation_time.class
=> Time
What I'd like to do is find those elements which match on a particular
range of "observation_time".  I'm used to Matlab and IDL programming
where one just does something like this:
indices = where( results.observation_time >= "2008-1-1" and
results.observation_time < "2009-1-1" )
What's the ruby way?  Obviously, I can't use Array.include? but
something like that would be nice.
Depends.  This might work (just an example)...
d = Time.now
e = Time.now + 1
f = Time.now + 2
(d..f).include? e
=> true

beware, though, since (d...e).include?(e) is false, but
(d...e).include?(d) is true.

Todd

shouldnt you do this kind of filtering on the ActiveRecord#find call?
 
R

Rob Redmon

snex said:
shouldnt you do this kind of filtering on the ActiveRecord#find call?

First, thank you for the varied and interesting suggestions. I always
learn a lot here!

My motivation is to present an inventory summary for scientific
observations. A sample is attached. From that motivation, I got
thinking about array processing in general and thus my question.

To create this view, I am greedily calling ActiveRecord#find many times
to essentially work with the same (24 * 366) rows. To me one call to
retrieve all of these rows and then pivot and filter them in local
memory makes more sense; it would be especially cool if I could use the
same "find" like calls without regard to whether the rows really came
from an AR connection or an already available resulset. Being used to
scientific analysis programming where we are always dealing with
multidimensional arrays, I wondered, isn't there a mechanism to operate
on an entire array, filtering on components which are "comparable"?
Consider the following IDL as pseudocode (Matlab would be similar).
This filter which gives data in the time range of "1990-1-1 12:00:00" to
"1990-1-1 12:59:59" would look like:

indices = where( data.observation_time >= julday( 1, 1, 1990, 12, 0,
0) ) and data.observation_time < julday( 1, 1, 1990, 13, 0, 0 ) )

However, it seems from these examples, I must implement this
functionality myself (when it becomes necessary). It seems to me I'll
need to write a function for each possible expression I might have which
essentially just iterates and performs that expression. Consider a
compound filter like (again in IDL):

indices = where( data.quality eq "good" and data.observation_time >=
julday( 1, 1, 1990, 12, 0, 0) ) and data.observation_time < julday( 1,
1, 1990, 13, 0, 0 ) )

This certainly maps very well to an ActiveRecord#find statement. But
what if I already have my resultset available? Or what if I'm not using
a database at all and I simply have an array of objects? For now, in
this database example, I am using ActiveRecord#find, but this situation
had me wondering about Ruby Array filtering in general. I recall way
back when I was in school and programming C++ for engineering analysis.
I wrote a sparse matrix library which overloaded "<" and "&&" to yield
the functionality above. Aren't usual comparison tokens already
overloaded somewhere to operate on arrays?

Thanks again for the great suggestions!!

Attachments:
http://www.ruby-forum.com/attachment/3637/BC840_1980_SAO.html.zip
 
C

Caleb Clausen

Joel's select/include? implementation is the normal way to solve this
particular problem, but if you're looking for a more general approach
to dealing with arrays and other ruby data structures, you might look
at Reg, my declarative language for matching ruby data structures.
With Reg, I would use this variation on Joel's code:

require 'rubygems'
require 'reg'
require 'time'

range = Time.parse("2008-1-1")...Time.parse("2009-1-1")
#results.select {|r| range.include? r.observation_time}
results.grep -{:eek:bservation_time=>range}

For most things Reg can do, it's syntax is shorter than the equivalent
imperative form, but it's not so big in simple cases like this.

http://rubyforge.org/projects/reg/
http://github.com/coatl/reg/
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,142
Latest member
arinsharma
Top