feature request: ${Sort} TLO

A forum for feature requests/discussions and user submitted patches that improve MQ2

Moderator: MacroQuest Developers

jdestefx
a lesser mummy
a lesser mummy
Posts: 55
Joined: Fri Jun 21, 2013 6:13 pm

feature request: ${Sort} TLO

Post by jdestefx » Sat May 26, 2018 12:41 am

Would be very handy to have a built in sorter TLO to handle simple sorting operations.

Maybe a good first start with minimal effort might be something like:

/declare a string local toon3_toon7_toon1_toon9

/varset a ${Sort[${a},_]} // returns -> toon1_toon3_toon7_toon9

JudgeD
a snow griffon
a snow griffon
Posts: 354
Joined: Sat Aug 18, 2012 8:07 pm

Re: feature request: ${Sort} TLO

Post by JudgeD » Thu May 31, 2018 8:31 pm

I wrote a macro sorter in the VIP section but I don't mind sharing here...

Someone was asking for an array sorter in slack the other day, so I wrote a fairly reusable array sorting include.

The way this is written is meant to allow for different types of arrays, and different types of comparers. Meaning, if you want to write a new compare sub and pass it in to do reverse alphabetical order, you can. Or you could write a comparer that works with int arrays, etc. This include also modifies the array in place without creating a duplicate array.

Of note, the Big-O runtime of this is lousy at O(n^2), but every time I've tested this it's been sub-second, so I don't think it matters for a macro.

Hack:
Also I noticed that when doing string.Compare[], if the string is surrounded by quotes it will always result in a negative comparison. This is probably a bug with core. To work around it, I strip away quotation marks (or anything that's a symbol) from the leading and trailing positions on the string. Any tips to make this cleaner I'd like to learn about.

SortArray.inc

Code: Select all

#warning

sub SortArray(String unsortedArrayName, String compareSubName)
	/declare i int local
	/declare j int local
	/declare temp string local
	
	/for i 1 to ${Math.Calc[${${unsortedArrayName}.Size} - 1]}
		/for j ${Math.Calc[${i} + 1]} to ${${unsortedArrayName}.Size}
			/if (${${compareSubName}[${${unsortedArrayName}[${i}]}, ${${unsortedArrayName}[${j}]}]}) {
				/varset temp ${${unsortedArrayName}[${i}]}
				/varset ${unsortedArrayName}[${i}] ${${unsortedArrayName}[${j}]}
				/varset ${unsortedArrayName}[${j}] ${temp}
			}
		/next j
	/next i
/return

sub AlphabeticalStringComparer(String a, string b)
	/varset a ${TrimStringQuotes[${a}]}
	/varset b ${TrimStringQuotes[${b}]}
		
	/if (${b.Length} == 0) /return FALSE
	/if (${a.Length} == 0) /return TRUE
/return (${a.Compare[${b}]} > 0)

sub TrimStringQuotes(String str)
	/if (${str.Left[1].Compare[a]} < 0) /varset str ${str.Right[${Math.Calc[${str.Length} - 1]}]}
	/if (${str.Right[1].Compare[a]} < 0) /varset str ${str.Left[${Math.Calc[${str.Length} - 1]}]}
/return ${str}

sub PrintArray(String arrayName)
	/declare index int local
	
	/for index 1 to ${${arrayName}.Size}
		/echo ${${arrayName}[${index}]}
	/next index
/return
Test Macro:

Code: Select all

#warning

#include SortArray.inc

sub main
	| Populate array
	/declare StringArray[10] string	outer
	/varset StringArray[1] "Jennifer"
	/varset StringArray[2] Becky
	/varset StringArray[3] Claire
	/varset StringArray[4] "Michelle"
	| Skip 5
	/varset StringArray[6] "Sarah"
	/varset StringArray[7] Althea
	/varset StringArray[8] Maggie
	| Skip 9, 10
	
	/echo Time: ${Time}
	/call SortArray "StringArray" "AlphabeticalStringComparer"
	/echo Time2: ${Time}
	
	/call PrintArray "StringArray"
	
	| Expected: Althea, Becky, Claire, "Jennifer", Maggie, "Michelle", "Sarah", "", "", ""
/return