Skip to content

Instantly share code, notes, and snippets.

@robotmay
Created April 24, 2012 12:09
Show Gist options
  • Save robotmay/2479149 to your computer and use it in GitHub Desktop.
Save robotmay/2479149 to your computer and use it in GitHub Desktop.
Find the closest date in an array of dates
# I have an array of dates (both past and present) and a single date ('needle' below),
# for which I want to find the closest date in either direction. Here's my solution;
# can you think of a better one?
dates.sort_by { |date| (date.to_time - needle.to_time).abs }.first
@danjohnson3141
Copy link

👍 Nice

@ddarbyson
Copy link

nice job

@flynn1982
Copy link

excellent!

@xiy
Copy link

xiy commented Jul 22, 2019

a fine vintage

@adelahayepm
Copy link

sort_by.first is also equivalent to min

dates.min { |date| (date.to_time - needle.to_time).abs }

@chiperific
Copy link

@adelahayepm, While what you say makes sense, it doesn't return the expected result in this context:

> dates
=>
["2019-12-30",                                                                              
 "2020-01-27",                                                                              
 "2020-02-24",                                                                              
 "2020-02-25",                                                                              
 "2020-10-22",                                                                              
 "2020-11-04",                                                                              
 "2021-01-06",                                                                              
 "2021-01-27",                                                                              
 "2021-02-03"]
> needle = '2020-03-01'
> dates.sort_by { |date| (date.to_date - needle.to_date).abs }.first
 => "2020-02-25" 
> dates.min { |date| (date.to_date - needle.to_date).abs }
 => "2019-12-30"

The .sort_by is providing a custom return array:

> dates.sort_by { |date| (date.to_date - needle.to_date).abs }
 => 
["2020-02-25",                                                                                                            
 "2020-02-24",                                                                                                            
 "2020-01-27",                                                                                                            
 "2019-12-30",                                                                                                            
 "2020-10-22",                                                                                                            
 "2020-11-04",                                                                                                            
 "2021-01-06",                                                                                                            
 "2021-01-27",                                                                                                            
 "2021-02-03"]

Calling .min on this will still find and return the smallest value, while .first is doing just what you'd expect.

In essence:

dates.min == dates.min { |date| (date.to_date - needle.to_date).abs }

@adelahayepm
Copy link

agree that my comment might not be on point after all, thanks for pointing that out @chiperific

funnily enough in this particular data set the min does work without the abs()

dates
=> [#<Date: 2019-12-30 ((2458848j,0s,0n),+0s,2299161j)>,                                               
 #<Date: 2020-01-27 ((2458876j,0s,0n),+0s,2299161j)>,                                               
 #<Date: 2020-02-24 ((2458904j,0s,0n),+0s,2299161j)>,                                               
 #<Date: 2020-02-25 ((2458905j,0s,0n),+0s,2299161j)>,                                               
 #<Date: 2020-10-22 ((2459145j,0s,0n),+0s,2299161j)>,                                               
 #<Date: 2020-11-04 ((2459158j,0s,0n),+0s,2299161j)>,                                               
 #<Date: 2021-01-06 ((2459221j,0s,0n),+0s,2299161j)>,                                        
 #<Date: 2021-01-27 ((2459242j,0s,0n),+0s,2299161j)>,                                        
 #<Date: 2021-02-03 ((2459249j,0s,0n),+0s,2299161j)>]   
dates.min { |date| date - needle }
#<Date: 2020-02-25 ((2458905j,0s,0n),+0s,2299161j)>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment