Multi-dimensional arrays on device

I’m unable to redim an array with multiple dimensions when testing on any device.

redim someArray(1,4) ///this doesn't work, changes the array's dimensions to (1879152656,8) ///and crashes if you try to use the array after that

Does anyone know some sort of work around for using multi dimensional arrays (that doesn’t include changing them to single-dimension arrays) in an app on a device?

Sort of a big bug, and it’s tricky since it works in the debugger but crashes on devices for me. I’ve already submitted a bug report but no response yet so I’m looking for maybe another way to achieve this in the meantime.

create your own array type

here is an example in SWIFT , should be easy to convert to XOJO
it uses a single dimension array, but acts like a 2D one

class Array2D<T> {
    let columns: Int
    let rows: Int
    var array: Array<T?>  // private

    init(columns: Int, rows: Int) {
        self.columns = columns
        self.rows = rows
        array = Array<T?>(count: rows*columns, repeatedValue: nil)
        ///     array = Array<T?>(count: rows*columns, repeatedValue: 0)
    }

    subscript(column: Int, row: Int) -> T? {
        get {
            return array[row*columns + column]
        }
        set(newValue) {
            array[row*columns + column] = newValue
        }
    }
}

replace “T” with datatype you want… “T” is kinda like a variant (but not quite) for Swift

isn’t “Variant” in the sense of Xojo variants.
This is a template class that lets you define a new class Array2d with a specific type, , for all of its member values.
It falls into the realm of “Generics”.

Internally a 2d Array in this class is an array of arrays of whatever type is.
In order to do this in Xojo you’d need to be able to declare something like.

dim arr() as Int()
which of course doesn’t compile

Try this (this is my 10 minute whip it together version so there can be bugs in the code :P)

Class Array2DOfInt

  Sub Constructor(rows as integer, columns as Integer)
		  self.columns = columns
		  self.rows = rows
		  contents = new dictionary
		  
		  for i as integer = 0 to rows - 1
		    dim tmp() as Integer
		    redim tmp(columns-1)
		    
		    contents.value(i) = tmp
		  next
		  
  End Sub


  Function operator_subscript(row as integer, column as integer) As integer
		  if not contents.hasKey(row-1) then
		    raise new OutOfBoundsException
		  end if
		  
		  if column-1 < 0 or column-1 >= columns then
		    raise new OutOfBoundsException
		  end if
		  
		  dim tmp() as integer = contents.value(row-1)
		  
		  return tmp(column-1)
		  
  End Function

  Sub operator_subscript(row as integer, column as integer, assigns v as integer)
		  if not contents.hasKey(row-1) then
		    raise new OutOfBoundsException
		  end if
		  
		  if column-1 < 0 or column-1 >= columns then
		    raise new OutOfBoundsException
		  end if
		  
		  dim tmp() as integer = contents.value(row-1)
		  
		  tmp(column-1) = v
		  
		  contents.value(row-1) = tmp
		  
  End Sub

  Protected columns As Integer
  Protected rows As Integer
  Protected contents As dictionary

end class

and use it like

[code]dim arr as new Array2DOfInt( 3, 4 )

for row as integer = 1 to 3
for column as integer = 1 to 4
arr(row , column) = 30+row*column // just so we dont have values that could be just the indexes
next
next

dim s as string

for row as integer = 1 to 3
s = s + "row " + str(row)
for column as integer = 1 to 4
dim i as integer = arr(row , column)
s = s + " col " + str(column) + " = " + str(i)
next
s = s + endofline
next

msgbox s[/code]

Right I was hoping not to have to do that. I’m trying to share a lot of code and classes between desktop & iOS and currently alllllllll of that code relies on multi-dimensional arrays. I would have to go back and change several hundred lines of code in the desktop apps to be able to do something like this.

I was thinking maybe a way of coming up with my own redim that just creates the array new every time.

Thanks Norman, I’ll have to look at that and figure out the implications. Much appreciated

Actually Norman, if you examine the code I posted closer you will notice that it is NOT an array of arrays. It is a SINGLE dimension array, where the X,Y coordinates are mathematically converted to a scalar Index…

And yes “T” is a Generic, which is why I said it was “kinda” like a variant

Not Tested… but this should be the translation, or something similar

class Array2D 
    protected nColumns As Integer
    protected nRows As Integer
    protected nArray() As Integer

    Sub Constructor(columns Integer, rows Integer) 
        nColumns = columns
        nRows = rows
        redim nArray(indexOf(rows,columns))
    End Sub

	 Private  Function indexOf(column Integer, row Integer) As Integer
	     dim indx as Integer=((row*nColumns)+column)
	     If indx<0 Or indx>nArray.Ubound Then
	        raise new OutOfBoundsException
	     End If
	     return indx
	  End Function
	  
    Function subscript(column Integer, row Integer) As Integer 
       Return nArray(indexOf(column,row)
    End Function
    
    Sub subscript(column Integer, row Integer,Assigns newValue as Integer) 
      nArray(indexOf(column,row) = newValue
    End Function
End Class

operator_subscript lets you use standard subscript style notation to access it
there’s very few examples hence why I used that
so you can use it in the same fashion as a real 2d array

[code]dim arr as new Array2DOfInt( 3, 4 )

for row as integer = 1 to 3
for column as integer = 1 to 4
arr(row , column) = 30+row*column // <<<<<<<<< uses operator_subscript (int, int , assigns int)
next
next
[/code]

[quote=200717:@Dave S]Actually Norman, if you examine the code I posted closer you will notice that it is NOT an array of arrays. It is a SINGLE dimension array, where the X,Y coordinates are mathematically converted to a scalar Index…
[/quote]
Indeed it is

[quote=200717:@Dave S]And yes “T” is a Generic, which is why I said it was “kinda” like a variant
[/quote]
… not really but Xojo doesn’t have generics so it is hard to suggest an equivalent concept

[quote=200717:@Dave S]Not Tested… but this should be the translation, or something similar

[code]
class Array2D
protected nColumns As Integer
protected nRows As Integer
protected nArray() As Integer

Sub Constructor(columns Integer, rows Integer) 
    nColumns = columns
    nRows = rows
    redim nArray(indexOf(rows,columns)) ///// <<<<<<< I think this is a bug and should be rows * columns
End Sub

[/code][/quote]

  redim nArray(indexOf(rows,columns)) ///// <<<<<<< I think this is a bug and should be rows * columns 

Not Rows * Columns but it should be Columns , Rows

but you said a flat array not a multi dimension one
multi dimensional arrays are what we’re replacing

they dont work on the device … otherwise this is a moot exercise

so you cant use a multi d array to emulate a multi d array

fwiw the code I posted does work in the IDE
did not test it on device

in the sim this works with the array 2d code I posted unchanged

[code] dim arr as new Array2DOfInt( 3, 4 )

for row as integer = 1 to 3
for column as integer = 1 to 4
arr(row , column) = 30+row*column // just so we dont have values that could be just the indexes
next
next

dim s as text

for row as integer = 1 to 3
s = s + "row " + row.ToText
for column as integer = 1 to 4
dim i as integer = arr(row , column)
s = s + " col " + column.ToText + " = " + i.ToText
next
s = s + &u0a
next

break[/code]

In the code I posted, just add another function (you will have to name is something other than ReDim ofcourse)


// add noError flag so Redim doesn't cause an exception when increasing size
Private  Function indexOf(column As Integer, row As Integer,noError as boolean=false) As Integer
	     dim indx as Integer=((row*nColumns)+column)
	     If indx<0 Or (indx>nArray.Ubound And noError=false) Then
	        raise new OutOfBoundsException
	     End If
	     return indx
	  End Function


Sub myRedim(column As Integer, row As Integer,noError as boolean=false) 
   ReDim nArray(indexOf(column,row,true)
End Sub