Every language has its own quirks when it comes to sorting data. In this post, I’ll take an introductory look at some of the most basic methods available for sorting data in EnScript. First, we need a list of some type of data that we want to sort. Our first example is going to use the ulong
type, which, in EnScript, is a 64-bit unsigned integer. You might use a ulong
if you were storing a list of file sizes, such as those presented by EntryClass::LogicalSize()
.
We’re going to declare a ulong
array type by using the typedef
statement as seen in line 3 below. On line 18, we’ll create our array with five values. One of the nicest things about arrays in EnScript is that they have a built-in Sort
function, and it takes options from the built-in class ArrayClass
. Lines 22, 25, and 28 demonstrate the differences in those options. Using ArrayClass::SORTENABLED
performs a default sort of the array in ascending order (smallest to largest). Adding ArrayClass::SORTDESCENDING
sorts in descending order (largest to smallest). Finally, adding ArrayClass::SORTNODUPE
removes duplicates from the array. This could be useful if you were trying to generate a list of unique values. Take a look through the example below and then check out the output section below it.
ulong Example:
class MainClass { typedef ulong[] ulongArray; void printArray(ulongArray array) { ulong curr; forall (ulong u in array) { Console.Write(u); if (++curr < array.Count()) { Console.Write("\t"); } } Console.Write("\n"); } void Main() { SystemClass::ClearConsole(); ulongArray array {548, 23, 164, 87, 164}; //Original order printArray(array); //Sort ascending array.Sort(ArrayClass::SORTENABLED); printArray(array); //Sort descending array.Sort(ArrayClass::SORTENABLED | ArrayClass::SORTDESCENDING); printArray(array); //Sort ascending, remove duplicates array.Sort(ArrayClass::SORTENABLED | ArrayClass::SORTNODUPE); printArray(array); } }
Output:
548 23 164 87 164 23 87 164 164 548 548 164 164 87 23 23 87 164 548
Take a look at the output of our code above. Are the results as you expected them? The first line contains the original list in its original order. The second line shows the list after it has been sorted in ascending order, the third after a descending order sort, and the fourth shows the list in ascending order after duplicates have been removed. Pretty straightforward, right? The options are the same for sorting other numerical types of arrays, such as int
, char
, and even DateClass
.
Next let’s take a look at sorting a String
array. When you’re dealing with everything in the same case, the options will look much the same as they did above. You’ll note that I threw in a different length string just so you can see how it’s sorted. Scroll down to see the output.
String Example:
class MainClass { typedef String[] StringArray; void printArray(StringArray array) { ulong curr; forall (String s in array) { Console.Write(s); if (++curr < array.Count()) { Console.Write("\t"); } } Console.Write("\n"); } void Main() { SystemClass::ClearConsole(); StringArray array {"abc", "abb", "aab", "aacd"}; //Original order printArray(array); //Sort ascending array.Sort(ArrayClass::SORTENABLED); printArray(array); //Sort descending array.Sort(ArrayClass::SORTENABLED | ArrayClass::SORTDESCENDING); printArray(array); } }
Output:
abc abb aab aacd aab aacd abb abc abc abb aacd aab
You’ll see that it sorts on the first letter, then moves on and sorts on the second letter, and so on. You can see that even though "aacd"
is a longer string than "abb"
and "abc"
, it is sorted before them, because the first and second letters "aa"
come before "ab"
of the latter two strings.
So what happens when we have mixed case strings? You can see on line 19 that all of the array members have the letters "abc"
in various mixed case. On line 23 we’re doing a standard ascending sort just like before. On line 26, however, we see a new option: ArrayClass::SORTCASE
. This option will turn on case sensitive sorting for strings. You can see its effect in the output below our code.
String Case Sensitive Example:
class MainClass { typedef String[] StringArray; void printArray(StringArray array) { ulong curr; forall (String s in array) { Console.Write(s); if (++curr < array.Count()) { Console.Write("\t"); } } Console.Write("\n"); } void Main() { SystemClass::ClearConsole(); //Create a new array with mixed case StringArray array {"abc", "Abc", "aBC", "abC", "ABc", "AbC"}; //Original order printArray(array); //Sort default - case insensitive array.Sort(ArrayClass::SORTENABLED); printArray(array); //Sort case sensitive array.Sort(ArrayClass::SORTENABLED | ArrayClass::SORTCASE); printArray(array); } }
Output:
abc Abc aBC abC ABc AbC Abc aBC abC ABc AbC abc ABc AbC Abc aBC abC abc
As usual, the first line shows the original order. The second line shows a case insensitive sort – if you converted all of the strings to lowercase, this is the sort you would get. The third line shows our new option – the case sensitive sort. You’ll quickly notice that the first three strings start with a capital "A"
and the last three start with a lowercase "a"
.
The last basic sorting functionality I’ll show you is for NameListClass
and NameValueClass
. Both of these types inherit from NodeClass
, and thus can take advantage of the NodeClass::INSERTSORTED
option when inserting a new node. You can see on lines 11 through 16 that we’ve used this option when inserting our NameValueClass
objects. This uses an extra line of code for each new object we insert into the list, but it allows us to perform a sorted insert instead of just the order we come upon the values. Both NameListClass
and NameValueClass
will be sorted on the string value of the Name()
property.
NameListClass and NameValueClass Example:
class MainClass { void Main() { SystemClass::ClearConsole(); NameValueClass stringList(); NameValueClass foo1(null, "abc", 0, "foo1"); NameValueClass bar(null, "abb", 0, "bar"); NameValueClass foo2(null, "abc", 0, "foo2"); NameValueClass baz(null, "aab", 0, "baz"); NameValueClass qux(null, "aac", 0, "qux"); NameValueClass foo3(null, "abc", 0, "foo3"); stringList.Insert(foo1, NodeClass::INSERTSORTED); stringList.Insert(bar, NodeClass::INSERTSORTED); stringList.Insert(foo2, NodeClass::INSERTSORTED); stringList.Insert(baz, NodeClass::INSERTSORTED); stringList.Insert(qux, NodeClass::INSERTSORTED); stringList.Insert(foo3, NodeClass::INSERTSORTED); forall (NameValueClass n in stringList) { Console.WriteLine(n.Name() + "(" + n.Value() + ")"); } } }
Output:
aab(baz) aac(qux) abb(bar) abc(foo3) abc(foo2) abc(foo1)
You can see that this works in the same manner that our string sort example did. It’s very interesting to note, however, the order that the items with the same value for Name()
(foo1
, foo2
, and foo3
) were sorted in. That is – they are sorted in reverse of the order in which they were inserted. The nodes are being inserted just before their value equivalents in the list. I actually find this quite annoying, though as long as we know the behavior we can work around it.
By now you should have a good understanding of the basics of sorting lists in EnScript. In the next post, I’ll show you how to sort arrays of user-defined class objects, and we’ll do some performance tests to see how the built-in array sorting algorithms hold up with large lists.