Feature request for a new sort method

We have:

  • Array.Sort
  • Array.Sort( AddressOf Method )
  • Array.SortWith( array1… [arrayn] )

but it would be nice to have:

  • Array.Sort( AddressOf Method, array1… [arrayn] )

For one, it would allow you to have a descending sort by defining a method, rather than looping backwards through the array. Which isn’t always why you want to sort arrays.

https://tracker.xojo.com/xojoinc/xojo/-/issues/69805

Why couldn’t you do your reverse sort thing with the version that takes a delegate?

Because I need to sort another array by the first one. I need SortWith with a delegate.

aSortData.SortWith( aCol1, aCol2, aCol3... etc )

but with a delegate.

I recently came up with a different need for Array.SortWith

I had a situation where I could have a variable numbers of arrays with the same number of elements that had to be sorted against an array that contained the times for the data points.

There is no good way to do that as there is no way to pass a variable number of arrays to Array.SortWith that I know of.

If that were ever supported one would need to be able to do

Array.SortWith VariantArray()

Where each element of the variant array held an array with the same number of elements as the base array…

But that syntax would be problematic. It would need to be special cased somehow to recognize that situation vs a variant array who’s elements you want directly sorted vs the elements of the arrays it holds.

I wound up changing my initial design so I did not have to do that, and luckily it was easy. (I did not initially know the times in some cases would not be sequential, and when they were, sometimes they would be in ascending and other times descending order)

The data cpme in as a bunch of tab delimited files with a time on each line.

I split the data file into lines and extracted the times into a their own array first and did a:
TimeArray.SortWith DataLinesArray
before I then split the data into separate objects by column (which needed to happen). That way all the data arrays in those objects would be sorted correctly with the time values they corresponded to.

Anyway having a way to be able to pass a variable number of arrays to Array.SortWith would be useful.

-Karen

I have almost the exact same issue. The inside of the call is simply a param array, however calling it with an indeterminate number of parameters is not possible.

If you could define a new array type paramArray and pass that it would work. For example:

Var aParams() as ParamArray
aParams.Add SomeArray1
aParams.Add SomeArray2
Etc

SortOrder.SortWith( aParams )

That could perhaps work. Or

Var aParams() as Pointer
aParams.Add AddressOf SomeArray1
aParams.Add AddressOf SomeArray2
Etc

SortOrder.SortWith( aParams )

For that situation, could you sort the index column using a Sort(delegate) and then use a SortWith? I realize it’s two steps but I think it might work.

We don’t like to use pointers for objects in pure Xojo. :grin: I would suggest:

Var arraysToSort() as Array

arraysToSort.Add names
arraysToSort.Add howManyApples
.
.
.

…which just looks redundant to this Xojo veteran but would be clearer syntactically. Pretty sure the compiler would need some serious reeducation to allow this, though. Arrays seem to be slightly special cased in the Xojo type system.

The problem with that is how does it know to sort the arrays contained with the array, rather than its contents.

Because every Array has a type (string, integer, etc). The sorting code could look at the type of objects contained in the Array and act accordingly.

Yes but you are effectively talking about having an array of arrays. Which is the same as an array of pointers.

No matter what the type you need to know if to sort the array passed or the the arrays pointed to. Ether could be required.

When we’re working in Xojo, we rarely need to consider the idea of pointers. Everything (well, almost everything) is an object, with the implementation details of that functionality left to the framework. So unless I’m in a situation where memory addresses are significant, like external functions, I don’t tend to worry about how an Array is referenced.

In my example, where you have arraysToSort() as Array, the framework could look at the group type of the items inside arraysToSort(). If it a collection of arrays, it sorts them using the contents of the array at item 0. If the parameter is an array and actually contains strings, for example, the strings themselves would be sorted.

An array of arrays is by definition an array of pointers, the only difference is in the name.

The issue still remains that there are plenty of use cases were you would want to sort the content of the array passed in, rather than the contents of the arrays pointed to my that array. Even when the array passed in is an array of arrays (or pointers)

To clarify this consider the following code:

Var array1(10) as integer
Var array2(10) as integer

Var outer() as Arrays = array( array1, array2 )

ASirtOrder.SortWith( outer )

How is Xojo supposed to know if you want to sort the contents of the array “outer” or the contents of the two arrays it points too. The method signatures would be identical, and both options are desirable.

Ps I’ve been using Xojo since around Realbasic 2.0.

Hmmm…

Var outer() as Arrays = array( array1, array2 )

ASortOrder.SortWithArrays( outer )

BTW I came in at RB3

-Karen

That’s about the only way I can see it could work. But it is getting slightly over complicated given I would also like a deligate version too.

I still think it is worthwhile though. If you accept the “as pointer” and “AddressOf” format then it is simply a matter of creating two new methods.

Arrays.SortWithArrays( arrays() as Pointer )
Arrays.SortWithArrays( AddressOf methodName, arrays() as Pointer )

The first would be almost identical to the current SortWith, without the param array in the function parameters. The second just has the deligate as well.

I thought these sort methods were just a convenience thing and if you want to get more complicated you just write your own sorting system? What you’ve mentioned there doesn’t seem that intuitive but I might have misread the thread.

@

I want the ability generalize code using Array.SortWith so one does not have to specify the arrays up front (the number of arrays and/or datatypes can vary).

Not being a pro, i suspect Xojo inc could (which would not mean they would) do an implementation faster than anything I could… ( But I do know not to do a bubble Sort for speed :wink: - I had to write one on an exam in the Fortran class I took back in college!)

That said, it’s not something I realistically expect Xojo inc to do…

I just have situations where that would be handy every so often, and ran into one about a week ago.

-Karen

Actually, the original request was for a simple extension to the three Sort methods and simply rounds out the set. A delegate version of SortWith. They provide a Sort with and without delegate but only SortWith without one.

Speed is indeed an issue with role your own sort. There is no Swap function in Xojo, which in VB provided a rapid exchange of two variables, which is very helpful is speeding up a sort.

It did kinda morph into SortWith a none pre specified version of SortWith.

I can’t see how I can use Sort(delegate) and keep track of which rows ended up in which order? Am I missing something. I’m currently building a key, in a rather dubious way, but it allows me to produce a two level sort and for each key to be either ascending or descending. Once I’ve built that key I am then using KeyArrray.SortWith( my other columns ). The issue being I’m not in control how how many other columns there will be. I’ve ended up doing the sort in chunks.

SortArrayBuild Key1, Key2, SortCache

For Col = Col1 To Col2 Step 10
  SortArrayCopy SortCache, SortData
  If Col + 10 <= Col2 Then
    SortData.SortWith( the next 10 columns )
    SGP.RunsCurrent = SGP.RunsCurrent + 10
    
  ElseIf Col + 9 <= Col2 Then
    SortData.SortWith( the next 9 columns )
    SGP.RunsCurrent = SGP.RunsCurrent + 9
    
  ElseIf Col + 8 <= Col2 Then
    SortData.SortWith( the next 8 columns )
    SGP.RunsCurrent = SGP.RunsCurrent + 8
    
  ElseIf Col + 7 <= Col2 Then
    SortData.SortWith( the next 7 columns )
    SGP.RunsCurrent = SGP.RunsCurrent + 7
    
  ElseIf Col + 5 <= Col2 Then
    SortData.SortWith( the next 6 columns )
    SGP.RunsCurrent = SGP.RunsCurrent + 6
    
  ElseIf Col + 4 <= Col2 Then
    SortData.SortWith( the next 5 columns )
    SGP.RunsCurrent = SGP.RunsCurrent + 5
    
  ElseIf Col + 3 <= Col2 Then
    SortData.SortWith( the next 4 columns )
    SGP.RunsCurrent = SGP.RunsCurrent + 4
    
  ElseIf Col + 2 <= Col2 Then
    SortData.SortWith( the next 3 columns )
    SGP.RunsCurrent = SGP.RunsCurrent + 3
    
  ElseIf Col + 1 <= Col2 Then
    SortData.SortWith( the next 2 columns )
    SGP.RunsCurrent = SGP.RunsCurrent + 2
    
  Else
    SortData.SortWith( the last column )
    SGP.RunsCurrent = SGP.RunsCurrent + 1
    
  End If
Next

Truely messy code but it takes 6 seconds to sort 184000 rows, compared with 16 for looping over each column in turn.

If I had

  • Array.SortWith( AddressOf Method, array1… [arrayn] )

I could sort my key and an array containing the row ordinal. Then I could simply reorder by rows in a single definitive way. Actually thinking about it I could use:

KeysArray.Sort( OrdinalArray )
And then copy the rows from a duplicate of my data in the order indicated by OrdinalArray.

Var aKey() as String
Var aOrdinal() as Integer
'Copy Your original data to another place:
For nRow = 0 to LastIndex
   For Col = 0 to LastColumn
      aBackupCols( Col ).Data( aOrdinal( nRow ) ) = Cols( Col ).Data( nRow )
   Next
   ' Build your key and the original row numbers
   aKey.Add GenerateKey( Key1, Order1, Key2, Order2, Row )
   aOrdinal.Add nRow
Next

' Sort by the Key keeping the row numbers in the new order
aKey.SortWith( aOrdinal )

For nRow = 0 to LastIndex
   For Col = 0 to LastColumn
      ' Copy the data back into your primary location but using the new row order.
      Cols( Col ).Data( nRow ) = aBackupCols( Col ).Data( aOrdinal( nRow ) )
   Next
Next

I mulled this over and I think I’ve got a pretty good solution. Take a look here:

http://ava.oxalyn.com/MultipleArraySorting.xojo_binary_project.zip

It is hampered somewhat by limitations of the language and some long-standing bugs concerning Variants. Until Xojo decides to make Arrays a class, or offer some other way to handle them in a generic fashion, there’s not much more than can be done. I’m sure there are or were good reasons for the current design but it does put pretty significant bounds on certain functionality.