Are you tired of pointers left in your duplicated arrays?

Hey guys, often when you are making a complex game we use arrays like objects holding many
different variable types and even arrays. Sometimes we have arrays nested in arrays, nested
in another array, ..... nested in yet another array. Is there a limit to how deep the rabbit hole goes?

I often find that duplicating the parent array to be tedious because there are always pointers being copied (references to the original array) and when I change data in one array the changes carry over to all arrays.

With this script, it will recursively dig down into the deepest recesses of your nested arrays and copy all of the data -- not the pointers.


Code:
/// array_duplicate(arr);
/// @param array[]
/*
    copy the contents of array
    to new array using recursive
    array handling -- making
    all data NEW, no pointers
    (Compatible with GMS1.4 and GMS2)
*/

var _source = argument0,                /// source array
    _size = array_length_1d(_source),   /// size of source array
    _dest = array_create(_size);        /// destination array
    
///--------------- Copy all data element-wise with loop
for (var i=0; i<_size; i++){
    /// if data in array is an array, duplicate that array as well
    if(is_array(_source[i])){
        /// recursively duplicate all nested arrays
        var _temp = array_duplicate(_source[i]);
        _dest[i] = _temp;
    } else {
        var _temp = _source[i];
        _dest[i] = _temp;
    }
};

return(_dest);
 

CloseRange

Member
I'm not sure if this post is actually asking a question or secretly trying to advertise your code, a bit sketchy if you ask me :eek:
that being said I've made some pretty big projects in lots of languages and lots of applications over the last 10 years and i'm not sure what you mean because it's rare that I ever have to create huge multi dimensional arrays let alone duplicate them and even more have to deal with lingering pointers.

Who know's maybe I'm just so used to it that I don't even think about it any more but 90% of my array use is 1 dimensional sometimes 2 in things like inventory systems.
I'm still in the cave ages of gm 1.x and so going past 2 dimensions is a lot harder for me anyway so when I do I just create multiple arrays and loop through them all.

Now you did ask a question I suppose....
Is there a limit to how deep the rabbit hole goes?
eh, yes and no. As far as the computer is concerned if you have a 2d array that's 10x10 that's the exact same as just a 1d array that's 100 big.
takes up the same amount of memory so technically you can keep going down the rabbit hole as long as you have memory to handle it.
techincally
arrays have the unique property in memory that they have to be ligned up in a row with eachother, imagine a bunch of kids holding hands, if they arn't next to eachother it doesn't work.
That means if the array is too big, game maker might not be able to find any place that has 100 or 1000 places of memory all in a row with nothing else to interfere (of course it might just move data around to make room)
That's why game maker has an array limit of about 32,000
Now what does that mean for multi dimensional arrays? it depends.
if it was truly an array of arrays, then a 200x200 array would break this limit.
But if game maker uses arrays of pointers to arrays then you could still do 32,000x32,000 (I believe this is the case)

But then there is really no difference from using multiple arrays vs a multi dimensional array. It uses the same amount of memory, it actually has faster search times, I don't gotta worry about duplicating them in weird ways (which i never do anyway....), and it keeps the code cleaner, so even if game maker 1.x had a better multi dimensial array system, i'd stick to my way.
 

curato

Member
I am not sure what the use case of this would be especially duplicating all that data in memory. You may want to rethink the data structure you are using to store your data.
 
Simpler approach:

Code:
var temp = ds_list_create();

temp[| 0] = orig_array;

var str = ds_list_write(temp);

ds_list_read(temp,str);

new_arrray = temp[| 0];

ds_list_destroy(temp);
 

FrostyCat

Redemption Seeker
I am not sure what the use case of this would be especially duplicating all that data in memory. You may want to rethink the data structure you are using to store your data.
The original poster is simply complaining about how a straight array_copy() makes a shallow copy of an array, and proposes a solution for making deep copies. With the caveat that it doesn't support current 2D arrays (but will if GML 2020 turns all 2D arrays into nested 1D arrays), it's fine.

He doesn't need to rethink his data structure, it's you who need to rethink how data can work. Data isn't always a flat collection of variables and 1D/2D arrays, and compositing different data structures into a nested structure is a perfectly valid technique. And when composition is involved, making deep, fully independent copies of these structures is an essential operation, and the current version of GML also happens to not have good built-in facilities for it.

Simpler approach:

Code:
var temp = ds_list_create();

temp[| 0] = orig_array;

var str = ds_list_write(temp);

ds_list_read(temp,str);

new_arrray = temp[| 0];

ds_list_destroy(temp);
Do ds_*_write() functions dig down nested array structures now? The last time I checked, they have these 2 weaknesses:
  • Inability to save nested structures beyond its topmost layer
  • Inability to interoperate between HTML5 and native exports
If either still holds, it still wouldn't be the cure-all to serialization that I see claimed all the time around here.
 
@FrostyCat, I've been using this trick for some time now, at least as far back as the old forums, so I can confirm it does correctly handle nested arrays. I've only tested it with lists, grids, and maps and can say the first two work, but does not work with maps, as they will still only save array pointers. As for the HTML5 issue, I cant say, as I've never owned said export.
 
Top