245 views

Sort multidimensional array by one of their values

1. 4 weeks ago

Pablo S

is not verified Sep 16
Edited 4 weeks ago

Y have a multidimensional array:

x(0,0) = 1
x(0,1) = 5
x(0,2) = 8

x(1,0) = 3
x(1,1) = 6
x(1,2) = 1

x(2,0) = 2
x(2,1) = 3
x(2,2) = 9

How can I sort the entire matrix taking only the third value (ubound 2) of each?

2. Markus W

Sep 16 Pre-Release Testers #JeSuisHuman New Zealand, Auc...

Copy those values into a new array and use sortWith?

3. Pablo S

is not verified Sep 16

Yes, I did that, but I thought there could be some function to sort directly without separating the array.
Thanks.

4. Norman P

Sep 16 Pre-Release Testers, Xojo Pro great-white-software.com/blog

multi dimensional array are not sortable using the array methods built in to Xojo
it would be possible to write a custom sort routine that did though

5. Douglas H

Sep 16 Pre-Release Testers, Xojo Pro

Could you refactor the multidimensional array as class instances? If so, you can do something like what is described in this blog entry.

6. Langue R

Sep 16

This has come up before and except for simple sorting cases I think the in-memory database approach seems to be the better way. You can find a recent discussion on this on the following post: https://forum.xojo.com/55796-sorting-data-array-or-dictionary-with-5-columns

7. Norman P

Sep 17 Pre-Release Testers, Xojo Pro great-white-software.com/blog

or just pull the specific column values into a one d array
and the row indexes into another

use sortwith on the values then access the specific rows through the indexes array

there are lots of ways to do something like this

8. Norman P

Sep 17 Pre-Release Testers, Xojo Pro great-white-software.com/blog

new desktop project
in window1.open event I have

Const limit = 199999
Dim r As New random
Dim orig(limit,2) As Integer

For i As Integer = 0 To limit
orig(i,0) = r.inrange(0,limit)
orig(i,1) = r.inrange(0,limit)
orig(i,2) = r.inrange(0,limit)
Next

Dim x(limit,2) As Integer
For i As Integer = 0 To limit
For j As Integer = 0 To 2
x(i,j) = orig(i,j)
Next
Next
// x(0,0) = 1
// x(0,1) = 5
// x(0,2) = 8
//
// x(1,0) = 3
// x(1,1) = 6
// x(1,2) = 1
//
// x(2,0) = 2
// x(2,1) = 3
// x(2,2) = 9

Dim startTime As Double = Microseconds
x.sortBy1(2)
Dim endTime As Double = Microseconds

Dim elapsed1 As Double = endTime - startTime

For i As Integer = 0 To limit
For j As Integer = 0 To 2
x(i,j) = orig(i,j)
Next
Next

startTime = Microseconds
x.sortBy2(2)
endTime = Microseconds

Dim elapsed2 As Double = endTime - startTime

Break

as well I added a module
in there I put

Public Sub SortBy1(extends arr(, ) as integer, column as integer)
Dim rows As Integer = ubound(arr,1)
Dim cols As Integer = ubound(arr,2)

Dim values() As Integer
Dim indexes() As Integer

For i As Integer = 0 To rows
values.append arr(i, column)
indexes.Append i
Next

values.SortWith indexes

Dim newarr(-1,-1) As Integer
Redim newarr(rows,cols)
For row As Integer = 0 To rows
Dim readRow As Integer = indexes(row)
For col As Integer = 0 To cols
Next
Next

Redim arr(-1,-1)
Redim arr(rows,cols)
For row As Integer = 0 To rows
For col As Integer = 0 To cols
arr(row,col) = newarr(row,col)
Next
Next

End Sub

and

Public Sub SortBy2(extends arr(, ) as integer, column as integer)
Dim rows As Integer = ubound(arr,1)
Dim cols As Integer = ubound(arr,2)

Dim sqlDB As New SQLiteDatabase
Call sqlDB.Connect
Dim colNames() As String
For i As Integer = 0 To cols
colNames.append "col" + Str(i)
Next
Dim sql As String = "create table temp(" + Join(colNames,",") + ")"
sqlDB.SQLExecute(sql)

sqldb.SQLExecute("begin transaction")
For row As Integer = 0 To rows

Dim colValues() As String
For col As Integer = 0 To cols
colValues.append Str(arr(row,col))
Next
sql = "insert into temp(" + Join(colNames,",") + ") values (" + Join(colValues,",") + ")"
sqlDB.SQLExecute(sql)

Next
sqldb.SQLExecute("commit transaction")

Redim arr(-1,-1)
Redim arr(rows,cols)
Dim rs As recordset
sql= "select * from temp order by " + colNames(column)
rs = sqlDB.SQLSelect(sql)
Dim row As Integer = 0
While rs <> Nil And rs.eof <> True

For col As Integer = 0 To cols
arr(row,col) = rs.idxFIeld(col+1).IntegerValue
Next

row = row + 1
rs.movenext
Wend
End Sub

the in place in memory version is much faster than the sqlite DB with this data set
BUT it will also use twice as much memory as the original array size 