Shpigford
Shpigford

Reputation: 25348

Select arrays between date ranges with Ruby

I have an array of arrays, I want to select arrays with a date that falls in a certain range.

ar = [[72162, "2014-01-21"], 
[53172, "2014-01-22"], 
[49374, "2014-01-23"], 
[41778, "2014-01-24"], 
[34182, "2014-01-25"], 
[58869, "2014-01-26"], 
[72162, "2014-01-27"], 
[43677, "2014-01-28"], 
[37980, "2014-01-29"], 
[87354, "2014-01-30"], 
[43677, "2014-01-31"]]

For example, I'd like to get all arrays between 2014-01-24 and 2014-01-29.

Upvotes: 0

Views: 2500

Answers (3)

Cary Swoveland
Cary Swoveland

Reputation: 110675

Without using Date:

ar.select { |_,d| d >= "2014-01-24" && d <= "2014-01-29" }

=> [[41778, "2014-01-24"],
    [34182, "2014-01-25"],
    [58869, "2014-01-26"],
    [72162, "2014-01-27"],
    [43677, "2014-01-28"],
    [37980, "2014-01-29"]]

or

ar.select { |_,d| ("2014-01-24".."2014-01-29").cover?(d) }

Note this depends on the date being expressed in year-month-day order.

Edit: I formerly used what I thought was Range#include?, but @toro2k pointed out that is was actually Enumerable#include?, which is quite slow. I had thought that Range#include? would be able to just compare endpoints, since <=> is defined for Strings. Not so; it only applies when the values are numeric or single character strings (else it supers to Enumerable#include?). That puzzled me. For anyone interested, I think I now understand the reason for the restricted application.

We would want ('aa'..'zz').include?('mno') to behave the same as

('aa'..'zz').to_a.include?('mno') => false

Suppose we do this:

class String
  alias :spaceship :<=>
  def <=>(other)
    spaceship(other.size > 1 ? other[0,2] : other)
  end
end

Then

"mno" >= 'aa' # => true
"mno" <= 'zz' # => true

so if Range#include? only considered the endpoints,

('aa'..'zz').include?("mno") # => true

Upvotes: 4

Arup Rakshit
Arup Rakshit

Reputation: 118271

I'd use Comparable#between?

ar = [ [72162, "2014-01-21"], 
       [53172, "2014-01-22"], 
       [49374, "2014-01-23"], 
       [41778, "2014-01-24"], 
       [34182, "2014-01-25"], 
       [58869, "2014-01-26"], 
       [72162, "2014-01-27"], 
       [43677, "2014-01-28"], 
       [37980, "2014-01-29"], 
       [87354, "2014-01-30"], 
       [43677, "2014-01-31"]
     ]

ar.select { |_,e| e.between?("2014-01-24","2014-01-29") }
# => [[41778, "2014-01-24"],
#     [34182, "2014-01-25"],
#     [58869, "2014-01-26"],
#     [72162, "2014-01-27"],
#     [43677, "2014-01-28"],
#     [37980, "2014-01-29"]]

Upvotes: 2

bjhaid
bjhaid

Reputation: 9762

require 'date'
range = Date.parse("2014-01-24")..Date.parse("2014-01-29")
ar.select { |x| range.include?(Date.parse(x[1])) }
=> [[41778, "2014-01-24"],
 [34182, "2014-01-25"],
 [58869, "2014-01-26"],
 [72162, "2014-01-27"],
 [43677, "2014-01-28"],
 [37980, "2014-01-29"]]

Upvotes: 2

Related Questions