Forum: Ruby Finding Matches in Array of Classes

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.
Rob R. (Guest)
on 2009-04-29 23:03
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
Todd B. (Guest)
on 2009-04-29 23:24
(Received via mailing list)
On Wed, Apr 29, 2009 at 2:03 PM, Rob R. <removed_email_address@domain.invalid>
wrote:
> => Time
> 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

Todd
Joel VanderWerf (Guest)
on 2009-04-29 23:25
(Received via mailing list)
Rob R. wrote:
>
>
> Rob

require 'time'
range = Time.parse("2008-1-1")..Time.parse("2009-1-1")
results.select {|r| range.include? r.observation_time}
Todd B. (Guest)
on 2009-04-29 23:26
(Received via mailing list)
On Wed, Apr 29, 2009 at 2:21 PM, Todd B. <removed_email_address@domain.invalid>
wrote:
>> results[0].observation_time.class
>> 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
7stud -. (Guest)
on 2009-04-30 11:15
Rob R. wrote:
> 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
7stud -. (Guest)
on 2009-04-30 11:17
7stud -- wrote:
>
> 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.
Todd B. (Guest)
on 2009-05-01 00:25
(Received via mailing list)
On Thu, Apr 30, 2009 at 2:17 AM, 7stud -- <removed_email_address@domain.invalid>
wrote:
> 7stud -- wrote:
>>
>> if in_a_minute.between?(now, in_two_minutes)
>>   puts 'yes1'
>> end

Nice.

Todd
snex (Guest)
on 2009-05-01 00:46
(Received via mailing list)
On Apr 29, 2:24 pm, Todd B. <removed_email_address@domain.invalid> wrote:
> >> The class of "observation_time" is:
> >> What's the ruby way?  Obviously, I can't use Array.include? but
> 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?
Rob R. (Guest)
on 2009-05-01 15:12
Attachment: BC840_1980_SAO.html.zip (0 Bytes)
snex wrote:
> On Apr 29, 2:24�pm, Todd B. <removed_email_address@domain.invalid> wrote:
>> >> The class of "observation_time" is:
>> >> What's the ruby way? �Obviously, I can't use Array.include? but
>> 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?

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!!
Caleb C. (Guest)
on 2009-05-01 20:53
(Received via mailing list)
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 -{:observation_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/
This topic is locked and can not be replied to.