Android Question How to quickly assign an array to another array by value (not by reference)?

Widget

Well-Known Member
Licensed User
Longtime User
How can I quickly assign an array to another array by value instead of by reference without using a LOOP?

Example:
I have a Sub that has an array parameter and I want to create a local array to manipulate the values of the local array WITHOUT modifying the values of the parameter array.

B4X:
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.

End Sub

Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.
  Private MyArray(10) As Int = Array As Int(1,2,3,4,5,6,7,8,9,10)

End Sub

Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    'Activity.LoadLayout("Layout1")

End Sub

Sub Activity_Resume
    TestArray(MyArray)
End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub ArrayToStr(aArray() As Int) As String
    Private SB As StringBuilder
    SB.Initialize
    For i=0 To aArray.Length-1
        SB.Append(aArray(i)).Append(" ")
    Next
    Return SB.ToString
End Sub

Sub TestArray(aArray() As Int)
    Log("aArray:" & ArrayToStr(aArray))
   
    Private locArray() As Int
    locArray = aArray
    locArray(1) = locArray(1) * 10
    Log("locArray:"&ArrayToStr(locArray))
   
    Log("MyArray:"&ArrayToStr(MyArray))
End Sub

Log:
aArray:1 2 3 4 5 6 7 8 9 10
locArray:1 20 3 4 5 6 7 8 9 10
MyArray:1 20 3 4 5 6 7 8 9 10

As you can see, when I use
locArray = aArray​
then change locArray(1), the passed parameter MyArray(1) also changes to 20.

What is an easy way to assign aArray to locArray (by value and not by reference) without using a loop?
There has to be a simple way of doing it, but for the life of me I can't seem to remember how.

TIA
 

DonManfred

Expert
Licensed User
Longtime User
You can use KeyValueStore for this

something like...

B4X:
Sub CopyArray(arr() As Int)
   kvs.PutObject("temp", arr)
   Return kvs.GetObject("temp")
End Sub
 
Upvote 0

Widget

Well-Known Member
Licensed User
Longtime User
You can use KeyValueStore for this

something like...

B4X:
Sub CopyArray(arr() As Int)
   kvs.PutObject("temp", arr)
   Return kvs.GetObject("temp")
End Sub

Gosh, I hadn't thought of using KVS. But that uses a SQLite database to store the array and then retrieve it to assign it to another array. It will probably work but is overkill and slow for a simple array assignment. :(

I was looking for something simple and fast. Maybe a one liner. I would have thought B4A would have something elegant like:
B4X:
'Wish Solution#1
locArray.Initialize(aArray)   'Unfortunately there is no Initialize method for Arrays (unless I write a sub to do it)

'Wish Solution#2
locArray = (aArray)         'I was hoping putting "(  )" around the array turns it into an expression which means it assigns elements by Value and not by Reference

But of course none of these "Wish Solutions" work so I guess I'll write a Sub to assign the array by value. Bummer if you ask me. :(
 
Last edited:
Upvote 0

Mahares

Expert
Licensed User
Longtime User
I was looking for something simple
What if you convert the array to a list and work with the list like this without affecting the original array:
B4X:
Private MyArray(10) As Int = Array As Int(1,2,3,4,5,6,7,8,9,10)
    Dim MyList As List
    MyList.Initialize
    MyList.AddAll(MyArray)
    Log(MyList.Get(1)*10)  'displsys : 20
 
Upvote 0

Widget

Well-Known Member
Licensed User
Longtime User
Yes, that is much better than using Sqlite. ;)
The Sub can take a List parameter and I can pass it an array, which gets converted to a List. This is the equivalent of passing the array by value to the Sub!

Now I can do something like:

B4X:
  Private MyArray(10) As Int = Array As Int(1,2,3,4,5,6,7,8,9,10)
  TestList(MyArray)

Sub TestList(aList As List)     'The sub converts Array argument to List (by Value)
    Log("Before")
    Log("aList:"&aList)
    Log("MyArray:"&ArrayToStr(MyArray))

    aList.Set(1, aList.Get(1)*10)   'Changing the aList parameter no longer changes the MyArray(1) argument
    Log("After")
    Log("aList:"&aList)
    Log("MyArray:"&ArrayToStr(MyArray))
End Sub

LOG:
Before
aList:(ArrayList) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
MyArray:1 2 3 4 5 6 7 8 9 10
After
aList:(ArrayList) [1, 20.0, 3, 4, 5, 6, 7, 8, 9, 10]
MyArray:1 2 3 4 5 6 7 8 9 10 <-- MyArray(1) no longer gets changed

This of course means the Sub() has to reference lists instead of an array which is fine if it is just my code. The code is less readable if I use Lists though.

But there are a lot of Android libraries that accept Arrays as parameters and not Lists like GradientDrawable.Initialize("TOP_BOTTOM", ColorArray). This means in these cases I will have to convert the List back to an array when necessary. Maybe I'll write a ListToIntArray() function for these cases.

I will have to decide whether to replace Arrays with Lists, or put up with the idiosyncrasies of Arrays.
 
Upvote 0

Widget

Well-Known Member
Licensed User
Longtime User
See Erel's replies in this post.

Post #8 is the best solution.

Thanks for the link.
BTW, B4XSerializator uses the in memory version of RandomAccessFile.ReadB4XObject.

It's a weird way of converting objects, by using a file (in memory), but I'll give it a try. I'll test it to see how fast it is. Normally when you do any type of I/O it slows things down because the OS has to get involved.
 
Upvote 0

Jeffrey Cameron

Well-Known Member
Licensed User
Longtime User
It's a weird way of converting objects

Agreed. I know very little actual Java, but I would think something like this _should_ work:
B4X:
' THIS DOES NOT WORK
Sub ArrayCopyOf(IntArray() As Int) As Int()
    Dim piArr(IntArray.Length) As Int
  
    Dim poJO As JavaObject
    poJO.InitializeStatic("java.util.Arrays")
    piArr = poJO.RunMethod("copyOf", Array As Object(IntArray, IntArray.Length))
  
    Return piArr
End Sub

It gives the error "java.lang.RuntimeException: Method: copyOf not found in: java.util.Arrays" when you hit the .RunMethod. Perhaps someone with more knowledge than I have can advise or explain?

[Edit] - This will work, see post #11 below.
 
Last edited:
Upvote 0

JordiCP

Expert
Licensed User
Longtime User
This would be the simplest solution (EDIT: oops, I see you already pointed it before!)
B4X:
  Dim B4XS As B4XSerializator
  Dim SecondArray() As Int = B4XS.ConvertBytesToObject(B4XS.ConvertObjectToBytes(MyArray))
The bad news is that it works for arrays of bytes, arrays of objects....but not for arrays of integers (not B4A thing, but Android limitation)


It gives the error "java.lang.RuntimeException: Method: copyOf not found in: java.util.Arrays" when you hit the .RunMethod. Perhaps someone with more knowledge than I have can advise or explain?
Your solution works fine for me with no errors :)
 
Last edited:
Upvote 0

Jeffrey Cameron

Well-Known Member
Licensed User
Longtime User
Your solution works fine for me with no errors :)

Figured it out, this routine will work with SDK 7+. The default manifest sets min SDK to 5, the Arrays.CopyOf method seems to require SDK 7 or higher.

It never occurred to me that this wasn't in the OS from day 1... :confused:
 
Upvote 0
Top