Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   Ruby (http://www.velocityreviews.com/forums/f66-ruby.html)
-   -   Sorting Dates and Times in an array (http://www.velocityreviews.com/forums/t839168-sorting-dates-and-times-in-an-array.html)

Paul 03-19-2007 04:20 PM

Sorting Dates and Times in an array
 
Hi there. I am having a bit of trouble trying to solve a particular
sorting problem with an array of data.

Please bear with me for a moment regarding the setup of this problem.
I don't currently have any control over the input data. I am just
trying to format the report of this data as per the requirement.

I have the following sample array data to work with:
@date_array = [['2/22/07','1:03 pm'],['3/9/07','10:45 pm'],
['3/1/07','1:52 pm'],['3/13/07','2:00 pm'],['2/28/07','10:45 am'],
['3/5/07','4:00 pm'],['2/14/07','5:00 pm'],['3/9/07','10:18 am'],
['3/13/07','11:15 am']]

(The actual array contains more data, but this is good enough to work
on this problem. BTW, date format = mm/dd/yy.)

Requirement:
1) Sort in descending order by Date (i.e. @date_array[x][0] )
2) Sort in ascending order by Time (i.e. @date_array[x][1] )

Elsewhere in the script, I use the following line to sort by a
particular element in a row:
> @fields.sort! { |a,b| b[ x ] <=> a[ x ] } # i.e. descending sort


This works quite nicely for string and numeric fields, but *not* for
Date or Time string fields. As an example, when I try it with the
above data I get the following:
----
puts 'Descending Sort - By Date:'
@date_array.sort! { |a,b| b[ 0 ] <=> a[ 0 ] }
@date_array.each_index do |row|
puts "row # #{row} = " + @date_array[row].join(" : ")
end
----
Descending Sort - By Date:
row # 0 = 3/9/07 : 10:18 am
row # 1 = 3/9/07 : 10:45 pm
row # 2 = 3/5/07 : 4:00 pm
row # 3 = 3/13/07 : 2:00 pm
row # 4 = 3/13/07 : 11:15 am
row # 5 = 3/1/07 : 1:52 pm
row # 6 = 2/28/07 : 10:45 am
row # 7 = 2/22/07 : 1:03 pm
row # 8 = 2/14/07 : 5:00 pm
----

--> Which is a nice string sort again, but not a date sort.

I know I'll have to write a method to deal with these two columns of
data, but I'm not sure where to start. I've tried googling solutions
in both this discussion group and the internet but so far haven't
turned up anything I can use.

Suggestions?


Olivier Renaud 03-19-2007 05:04 PM

Re: Sorting Dates and Times in an array
 
Le lundi 19 mars 2007 17:25, Paul a =E9crit=A0:
> Hi there. I am having a bit of trouble trying to solve a particular
> sorting problem with an array of data.
>
> Please bear with me for a moment regarding the setup of this problem.
> I don't currently have any control over the input data. I am just
> trying to format the report of this data as per the requirement.
>
> I have the following sample array data to work with:
> @date_array =3D [['2/22/07','1:03 pm'],['3/9/07','10:45 pm'],
> ['3/1/07','1:52 pm'],['3/13/07','2:00 pm'],['2/28/07','10:45 am'],
> ['3/5/07','4:00 pm'],['2/14/07','5:00 pm'],['3/9/07','10:18 am'],
> ['3/13/07','11:15 am']]
>
> (The actual array contains more data, but this is good enough to work
> on this problem. BTW, date format =3D mm/dd/yy.)
>
> Requirement:
> 1) Sort in descending order by Date (i.e. @date_array[x][0] )
> 2) Sort in ascending order by Time (i.e. @date_array[x][1] )
>
> Elsewhere in the script, I use the following line to sort by a
>
> particular element in a row:
> > @fields.sort! { |a,b| b[ x ] <=3D> a[ x ] } # i.e. descending sort

>
> This works quite nicely for string and numeric fields, but *not* for
> Date or Time string fields. As an example, when I try it with the
> above data I get the following:
> ----
> puts 'Descending Sort - By Date:'
> @date_array.sort! { |a,b| b[ 0 ] <=3D> a[ 0 ] }
> @date_array.each_index do |row|
> puts "row # #{row} =3D " + @date_array[row].join(" : ")
> end
> ----
> Descending Sort - By Date:
> row # 0 =3D 3/9/07 : 10:18 am
> row # 1 =3D 3/9/07 : 10:45 pm
> row # 2 =3D 3/5/07 : 4:00 pm
> row # 3 =3D 3/13/07 : 2:00 pm
> row # 4 =3D 3/13/07 : 11:15 am
> row # 5 =3D 3/1/07 : 1:52 pm
> row # 6 =3D 2/28/07 : 10:45 am
> row # 7 =3D 2/22/07 : 1:03 pm
> row # 8 =3D 2/14/07 : 5:00 pm
> ----
>
> --> Which is a nice string sort again, but not a date sort.
>
> I know I'll have to write a method to deal with these two columns of
> data, but I'm not sure where to start. I've tried googling solutions
> in both this discussion group and the internet but so far haven't
> turned up anything I can use.
>
> Suggestions?



Hi Paul,

You may want to first convert your dates/times to real Time objects, so tha=
t=20
they can be compared.

Here is my solution :

require 'pp'
pp @date_array.sort_by {|ary| ary.map{|elt| Time.parse(elt) } }
[["2/14/07", "5:00 pm"],
["2/22/07", "1:03 pm"],
["2/28/07", "10:45 am"],
["3/1/07", "1:52 pm"],
["3/5/07", "4:00 pm"],
["3/9/07", "10:18 am"],
["3/9/07", "10:45 pm"],
["3/13/07", "11:15 am"],
["3/13/07", "2:00 pm"]]
=3D> nil

A quick explanation :
@date_array is sorted with sort_by, because we want to sort the array=20
according to a simple criteria. For the comparison, each element of the arr=
ay=20
(ie the date and the time string) is converted to a Time object with=20
Time#parse, and is kept in an array (this is why I used #map).

Doing so, the original arrays of Strings will be sorted, according to the=20
order of the Arrays containing the real Time objects. For example on a sing=
le=20
element of your original array :
["2/14/07", "5:00 pm"].map{|el| Time.parse(el)}
=3D> [Wed Feb 14 00:00:00 +0100 2007, Mon Mar 19 17:00:00 +0100 2007]


Instead of comparing arrays that contains one element for the date and anot=
her=20
element for the time, we could have created only one Time object representi=
ng=20
both :

@date_array.sort_by {|ary| Time.parse("#{ary.first} #{ary.last}") }

Regards.

=2D-=20
Olivier Renaud


Rob Biedenharn 03-19-2007 05:10 PM

Re: Sorting Dates and Times in an array
 

On Mar 19, 2007, at 12:25 PM, Paul wrote:

> Hi there. I am having a bit of trouble trying to solve a particular
> sorting problem with an array of data.
>
> Please bear with me for a moment regarding the setup of this problem.
> I don't currently have any control over the input data. I am just
> trying to format the report of this data as per the requirement.
>
> I have the following sample array data to work with:
> @date_array = [['2/22/07','1:03 pm'],['3/9/07','10:45 pm'],
> ['3/1/07','1:52 pm'],['3/13/07','2:00 pm'],['2/28/07','10:45 am'],
> ['3/5/07','4:00 pm'],['2/14/07','5:00 pm'],['3/9/07','10:18 am'],
> ['3/13/07','11:15 am']]
>
> (The actual array contains more data, but this is good enough to work
> on this problem. BTW, date format = mm/dd/yy.)
>
> Requirement:
> 1) Sort in descending order by Date (i.e. @date_array[x][0] )
> 2) Sort in ascending order by Time (i.e. @date_array[x][1] )
>
> Elsewhere in the script, I use the following line to sort by a
> particular element in a row:
>> @fields.sort! { |a,b| b[ x ] <=> a[ x ] } # i.e. descending sort

>
> This works quite nicely for string and numeric fields, but *not* for
> Date or Time string fields. As an example, when I try it with the
> above data I get the following:
> ----
> puts 'Descending Sort - By Date:'
> @date_array.sort! { |a,b| b[ 0 ] <=> a[ 0 ] }
> @date_array.each_index do |row|
> puts "row # #{row} = " + @date_array[row].join(" : ")
> end
> ----
> Descending Sort - By Date:
> row # 0 = 3/9/07 : 10:18 am
> row # 1 = 3/9/07 : 10:45 pm
> row # 2 = 3/5/07 : 4:00 pm
> row # 3 = 3/13/07 : 2:00 pm
> row # 4 = 3/13/07 : 11:15 am
> row # 5 = 3/1/07 : 1:52 pm
> row # 6 = 2/28/07 : 10:45 am
> row # 7 = 2/22/07 : 1:03 pm
> row # 8 = 2/14/07 : 5:00 pm
> ----
>
> --> Which is a nice string sort again, but not a date sort.
>
> I know I'll have to write a method to deal with these two columns of
> data, but I'm not sure where to start. I've tried googling solutions
> in both this discussion group and the internet but so far haven't
> turned up anything I can use.
>
> Suggestions?


>> epoch = Time.at(0).utc

=> Thu Jan 01 00:00:00 UTC 1970
>> @date_array.sort_by {|d,t| dp=Date.parse(d,true); tp=Time.parse

(t,epoch); [ Date.today - dp, tp ] }.each {|d,t| puts("%8s %8s" %
[d,t]) }
3/13/07 11:15 am
3/13/07 2:00 pm
3/9/07 10:18 am
3/9/07 10:45 pm
3/5/07 4:00 pm
3/1/07 1:52 pm
2/28/07 10:45 am
2/22/07 1:03 pm
2/14/07 5:00 pm
=> [["3/13/07", "11:15 am"], ["3/13/07", "2:00 pm"], ["3/9/07",
"10:18 am"], ["3/9/07", "10:45 pm"], ["3/5/07", "4:00 pm"],
["3/1/07", "1:52 pm"], ["2/28/07", "10:45 am"], ["2/22/07", "1:03
pm"], ["2/14/07", "5:00 pm"]]

Parse the date with 2-digit year semantics (1969-2068 from the 'true'
arg) and parse the time based on the beginning of the epoch (really
any date would do). The sort is then reversed by date and forward by
time when dates are equal.

The use of .sort_by causes the keys to be processed once and is
better for large Arrays than .sort (and if you need .sort!, just do
@date_array = @date_array.sort_by {...} instead).

-Rob

Rob Biedenharn http://agileconsultingllc.com
Rob@AgileConsultingLLC.com




Robert Klemme 03-19-2007 05:21 PM

Re: Sorting Dates and Times in an array
 
On 19.03.2007 18:04, Olivier Renaud wrote:

> Instead of comparing arrays that contains one element for the date and another
> element for the time, we could have created only one Time object representing
> both :
>
> @date_array.sort_by {|ary| Time.parse("#{ary.first} #{ary.last}") }


I think this does not meet the OP's requirements (because of descending
date).

epoch = Date.new(0)
@date_array.sort_by {|dt,tm| [epoch - Date.parse(dt), Time.parse(tm)]}

Substraction with epoch will make date components negative and thus lead
to descending ordering.

Kind regards

robert

Rick DeNatale 03-19-2007 05:25 PM

Re: Sorting Dates and Times in an array
 
On 3/19/07, Paul <tester.paul@gmail.com> wrote:
> Hi there. I am having a bit of trouble trying to solve a particular
> sorting problem with an array of data.
>
> Please bear with me for a moment regarding the setup of this problem.
> I don't currently have any control over the input data. I am just
> trying to format the report of this data as per the requirement.
>
> I have the following sample array data to work with:
> @date_array = [['2/22/07','1:03 pm'],['3/9/07','10:45 pm'],
> ['3/1/07','1:52 pm'],['3/13/07','2:00 pm'],['2/28/07','10:45 am'],
> ['3/5/07','4:00 pm'],['2/14/07','5:00 pm'],['3/9/07','10:18 am'],
> ['3/13/07','11:15 am']]
>
> (The actual array contains more data, but this is good enough to work
> on this problem. BTW, date format = mm/dd/yy.)
>
> Requirement:
> 1) Sort in descending order by Date (i.e. @date_array[x][0] )
> 2) Sort in ascending order by Time (i.e. @date_array[x][1] )


(Standard Library) objects are your friend.

rick@frodo:/public/rubyscripts$ cat datesort.rb
date_array = [['2/22/07','1:03 pm'],['3/9/07','10:45 pm'],
['3/1/07','1:52 pm'],['3/13/07','2:00 pm'],['2/28/07','10:45 am'],
['3/5/07','4:00 pm'],['2/14/07','5:00 pm'],['3/9/07','10:18 am'],
['3/13/07','11:15 am']]

p date_array.sort do |a, b|
ddiff = Date.parse(b[0],true) <=> Date.parse(a[0],true)
ddiff == 0 ? Time.parse(a[0]) <=> Time.parse(b[0]) : ddiff
end

rick@frodo:/public/rubyscripts$ ruby datesort.rb
[["2/14/07", "5:00 pm"], ["2/22/07", "1:03 pm"], ["2/28/07", "10:45
am"], ["3/1/07", "1:52 pm"], ["3/13/07", "11:15 am"], ["3/13/07",
"2:00 pm"], ["3/5/07", "4:00 pm"], ["3/9/07", "10:18 am"], ["3/9/07",
"10:45 pm"]]
rick@frodo:/public/rubyscripts$


--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

IPMS/USA Region 12 Coordinator
http://ipmsr12.denhaven2.com/

Visit the Project Mercury Wiki Site
http://www.mercuryspacecraft.com/


Olivier Renaud 03-19-2007 05:29 PM

Re: Sorting Dates and Times in an array
 
Le lundi 19 mars 2007 18:25, Robert Klemme a =E9crit=A0:
> On 19.03.2007 18:04, Olivier Renaud wrote:
> > Instead of comparing arrays that contains one element for the date and
> > another element for the time, we could have created only one Time object
> > representing both :
> >
> > @date_array.sort_by {|ary| Time.parse("#{ary.first} #{ary.last}") }

>
> I think this does not meet the OP's requirements (because of descending
> date).
>
> epoch =3D Date.new(0)
> @date_array.sort_by {|dt,tm| [epoch - Date.parse(dt), Time.parse(tm)]}
>
> Substraction with epoch will make date components negative and thus lead
> to descending ordering.
>
> Kind regards
>
> robert


Yes you're right, I just kept in mind the instruction "sort the dates !". B=
ut=20
I missed the subtlelty. Thanks.

=2D-=20
Olivier Renaud


Rick DeNatale 03-19-2007 06:16 PM

Re: Sorting Dates and Times in an array
 
On 3/19/07, Rob Biedenharn <Rob@agileconsultingllc.com> wrote:

> The use of .sort_by causes the keys to be processed once and is
> better for large Arrays than .sort (and if you need .sort!, just do
> @date_array = @date_array.sort_by {...} instead).


Not exactly the same if you have more than one reference to the Array.
A more general equivalent to sort! would be:

@date_array.replace(@date_array.sort_by {...})

Another one of those sometimes subtle differences between variables and objects.
--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/


Rob Biedenharn 03-19-2007 06:18 PM

Re: Sorting Dates and Times in an array
 

On Mar 19, 2007, at 1:25 PM, Rick DeNatale wrote:

> On 3/19/07, Paul <tester.paul@gmail.com> wrote:
>> Hi there. I am having a bit of trouble trying to solve a particular
>> sorting problem with an array of data.
>>
>> Please bear with me for a moment regarding the setup of this problem.
>> I don't currently have any control over the input data. I am just
>> trying to format the report of this data as per the requirement.
>>
>> I have the following sample array data to work with:
>> @date_array = [['2/22/07','1:03 pm'],['3/9/07','10:45 pm'],
>> ['3/1/07','1:52 pm'],['3/13/07','2:00 pm'],['2/28/07','10:45 am'],
>> ['3/5/07','4:00 pm'],['2/14/07','5:00 pm'],['3/9/07','10:18 am'],
>> ['3/13/07','11:15 am']]
>>
>> (The actual array contains more data, but this is good enough to work
>> on this problem. BTW, date format = mm/dd/yy.)
>>
>> Requirement:
>> 1) Sort in descending order by Date (i.e. @date_array[x][0] )
>> 2) Sort in ascending order by Time (i.e. @date_array[x][1] )

>
> (Standard Library) objects are your friend.
>
> rick@frodo:/public/rubyscripts$ cat datesort.rb
> date_array = [['2/22/07','1:03 pm'],['3/9/07','10:45 pm'],
> ['3/1/07','1:52 pm'],['3/13/07','2:00 pm'],['2/28/07','10:45 am'],
> ['3/5/07','4:00 pm'],['2/14/07','5:00 pm'],['3/9/07','10:18 am'],
> ['3/13/07','11:15 am']]
>
> p date_array.sort do |a, b|
> ddiff = Date.parse(b[0],true) <=> Date.parse(a[0],true)
> ddiff == 0 ? Time.parse(a[0]) <=> Time.parse(b[0]) : ddiff
> end



I think this was meant to be (note Time.parse(a[ 1 ]) not [0])

p date_array.sort do |a,b|
(Data.parse(b[0],true) <=> Date.parse(a[0],true)).nonzero? ||
Time.parse(a[1]) <=> Time.parse(b[1])
end

> rick@frodo:/public/rubyscripts$ ruby datesort.rb
> [["2/14/07", "5:00 pm"], ["2/22/07", "1:03 pm"], ["2/28/07", "10:45
> am"], ["3/1/07", "1:52 pm"], ["3/13/07", "11:15 am"], ["3/13/07",
> "2:00 pm"], ["3/5/07", "4:00 pm"], ["3/9/07", "10:18 am"], ["3/9/07",
> "10:45 pm"]]
> rick@frodo:/public/rubyscripts$
>
>
> --
> Rick DeNatale
>
> My blog on Ruby
> http://talklikeaduck.denhaven2.com/
>
> IPMS/USA Region 12 Coordinator
> http://ipmsr12.denhaven2.com/
>
> Visit the Project Mercury Wiki Site
> http://www.mercuryspacecraft.com/
>


Rob Biedenharn http://agileconsultingllc.com
Rob@AgileConsultingLLC.com
+1 513-295-4739
Skype: rob.biedenharn




Rick DeNatale 03-19-2007 06:40 PM

Re: Sorting Dates and Times in an array
 
On 3/19/07, Rob Biedenharn <Rob@agileconsultingllc.com> wrote:

>
> I think this was meant to be (note Time.parse(a[ 1 ]) not [0])


Right you are.


--
Rick


Paul 03-19-2007 07:57 PM

Re: Sorting Dates and Times in an array
 
On Mar 19, 1:21 pm, Robert Klemme wrote:
> I think this does not meet the OP's requirements (because of descending
> date).
>
> epoch = Date.new(0)
> @date_array.sort_by {|dt,tm| [epoch - Date.parse(dt), Time.parse(tm)]}
>
> Substraction with epoch will make date components negative and thus lead
> to descending ordering.
>


Hello Robert, I tried this but I get the following errors:

irb(main):003:0> epoch = Date.new(0)
ArgumentError: wrong number of arguments (1 for 0)
from (irb):3:in `initialize'
from (irb):3

irb(main):005:0> @date_array.sort_by {|dt,tm| [epoch - Date.parse(dt),
Time.parse(tm)]}
NoMethodError: undefined method `parse' for Date:Class
from (irb):5
from (irb):5:in `sort_by'
from (irb):5

Am I missing a 'require' or something to make your lines work?



All times are GMT. The time now is 08:13 AM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.