Notifications
Clear all

[Closed] Sorting dates

So, I have an array of dates in this format: 4 digit year, 2 digit month, 2 digit date

ex: #(2011.01.15, 2009.01.15, 2011.05.16, 2010.05.22)

  1. Does max have a built in function to sort these newest to oldest?
  2. If not, would this algorithm basically be a filterString by period, then quicksort on the years, then a quicksort on the months, then a quicksort on the days?
  3. If not, what would be the fastest way to soft these dates?

Thanks!

10 Replies

In this specific format, regular string-based sorting should work.

sort #("2011.01.15", "2009.01.15", "2011.05.16", "2010.05.22")
--> #("2009.01.15", "2010.05.22", "2011.01.15", "2011.05.16")

thanks bobo! that does exactly what i wanted it to do!

actually, after sorting, i needed the array to be flipped from oldest first to newest first.
so here’s what i wrote to do that, in case any one else needs such code
and also, if you know of a better way to do this – I’d like to know


--flip the array
local mySortedArray = #()
while myFilteredNames.count > 0 do
(
append mySortedArray myFilteredNames[myFilteredNames.count]
myFilteredNames.count = (myFilteredNames.count-1)
)


  fn reverseStringSort s1 s2 = (stricmp s2 s1)
  qsort str_array reverseStringSort
  

Or the less intimidating but slower alternative,

theArray = #("2011.01.15", "2009.01.15", "2011.05.16", "2010.05.22")
 sort theArray --sort forward
 theArray = for i = theArray.count to 1 by -1 collect theArray[i] --collect backwards
-->#("2011.05.16", "2011.01.15", "2010.05.22", "2009.01.15")

slower but memory friendly:


for k=1 to arr.count/2 do swap arr[k] arr[arr.count-k+1]

i have so much to learn from both of you

I wanted to learn more about the code you guys posted, so I went ahead and put them all into a script and time stamped them operating on an array with 500,000 date entries. Here are the results of my tests:


    "Array built and sorted in 10.8sec with 500,000 entries."
    "Sort in 2.3sec."
    "DenisT#1 sort in 7.8sec."
    "Bobo sort in 0.9sec."
    "DenisT#2 sort in 0.6sec."
Here is the code I used to arrive at the above data:
(
  	myArray = #()
  	local start = timeStamp()
  	for i = 1 to 500000 do 
  	(
  		local myRandomYear = (random 2010 2011)
  		local myRandomMonth = (random 01 12)
  		local myRandomDay = (random 01 28)
  		
  		--pad a 0 before single digit values
  		if myRandomMonth < 10 then (myRandomMonth = "0" + myRandomMonth as string);myRandomMonth as integer
  		if myRandomDay < 10 then (myRandomDay = "0" + myRandomDay as string);myRandomDay as integer
  		
  		local myDateString = myRandomYear as string + "," + myRandomMonth as string + "," + myRandomDay as string
  		append myArray myDateString
  	)
  	sort myArray --sort forward
  	theFeedbackTxt = "Array built and sorted in " + (formattedPrint ((timeStamp() - start) / 1000.0) format:".1f") + "sec with 500,000 entries."
  	print theFeedbackTxt
  
  	/*
  	--time stamp method
  	local mySortedArray = #()
  	local start = timeStamp()
  	
  	while myArray.count > 0 do
  	(
  	append mySortedArray myArray[myArray.count]
  	myArray.count = (myArray.count-1)
  	)
  	theFeedbackTxt = "Sort in " + (formattedPrint ((timeStamp() - start) / 1000.0) format:".1f") + "sec."
  	print theFeedbackTxt
  	*/
  
  	/*
  	--time stamp denisT's method #1
  	local start = timeStamp()
  	fn reverseStringSort s1 s2 = (stricmp s2 s1)
  	qsort myArray reverseStringSort
  	theFeedbackTxt = "DenisT#1 sort in " + (formattedPrint ((timeStamp() - start) / 1000.0) format:".1f") + "sec."
  	print theFeedbackTxt
  	*/
  
  	/*
  	--time stamp bobo's method #1
  	local start = timeStamp()
  	myArray = for i = myArray.count to 1 by -1 collect myArray[i] --collect backwards
  	theFeedbackTxt = "Bobo sort in " + (formattedPrint ((timeStamp() - start) / 1000.0) format:".1f") + "sec."
  	print theFeedbackTxt
  	*/
  	
  	--/*
  	--time stamp denisT's method #2
  	local start = timeStamp()
  	for k=1 to myArray.count/2 do swap myArray[k] myArray[myArray.count-k+1]
  	theFeedbackTxt = "DenisT#2 sort in " + (formattedPrint ((timeStamp() - start) / 1000.0) format:".1f") + "sec."
  	print theFeedbackTxt
  	--*/
  )
Looks like denisT's 2nd method works the fastest: 

for k=1 to myArray.count/2 do swap myArray[k] myArray[myArray.count-k+1]

I’ve yet to do any memory tests to see which handles the array better, but I’ll make the assumption that denisT’s 2nd method probably wins here as well.

1 Reply
(@denist)
Joined: 2 years ago

Posts: 0

first of all the method that you use for comparison is not correct. The methods has to sort exactly same arrays.
here is correct method for 50,000 entities:


  seed 0
  defdata = for k=1 to 50000 collect
  ( 
  	y = random 1967 2011
  	m = random 1 12
  	d = random 1 31
  	(formattedPrint y format:".4d.") + (formattedPrint m format:".2d.") + (formattedPrint d format:".2d")
  )
  (gc())
  
  -- TheGrak
  (
  	data = copy defdata #nomap
  	gc()	
  
  	t1 = timestamp()
  	m1 = heapfree
  	sort data
  	local sortedData = #()
  	  
  	  while data.count > 0 do
  	  (
  		append sortedData data[data.count]
  		data.count = (data.count-1)
  	  )
  	m2 = heapfree
  	format "TheGrak 	-> time:% memory:%
" (timestamp() - t1) (m1 - m2)
  )
  -- Bobo
  (
  	data = copy defdata #nomap
  	gc()	
  
  	t1 = timestamp()
  	m1 = heapfree
  	sort data
  	for i = data.count to 1 by -1 collect data[i]
  	m2 = heapfree
  	format "Bobo 		-> time:% memory:%
" (timestamp() - t1) (m1 - m2)
  )
  -- denisT #1
  (
  	fn reverseStringSort s1 s2 = (stricmp s2 s1)
  	data = copy defdata #nomap
  	gc()	
  
  	t1 = timestamp()
  	m1 = heapfree
  	qsort data reverseStringSort
  	m2 = heapfree
  	format "denisT #1 	-> time:% memory:%
" (timestamp() - t1) (m1 - m2)
  )
  -- denisT #2
  (
  	data = copy defdata #nomap
  	gc()	
  
  	t1 = timestamp()
  	m1 = heapfree
  	sort data
  	count = data.count
  	for k=1 to count/2 do swap data[k] data[count-k+1]
  	m2 = heapfree
  	format "denisT #2 	-> time:% memory:%
" (timestamp() - t1) (m1 - m2)
  )
  

as you see the fastest methods is Bobo’s.
the safest (speed + memory) is denisT’s #2.

QSORT function is very slow as compared with SORT and uses a lot of memory. But usually when you need to sort by Date/Time you have to sort some structures (“File, Date” for example). In this case the SORT function doesn’t work anymore and we have to use another methods. But if we use structure we don’t need to store DATE in STRING format. We can convert DATE to INTEGER. In this case the QSORT will work faster and more friendly for memory.

DenisT, thanks for the post. I always like studying your code!