SOLVED array_delete() not working as expected...

FoxyOfJungle

Kazan Games
Hello!

I've been trying to solve this for a while, but it seems to me a GMS 2 bug maybe (or not?).


I'm gonna explain:
1 - I create an array of structs;
2 - I loop through the array and try to delete all items, but it doesn't delete everything, it skips some...


See:

GML:
array[0] = {
    aa : 0
}
array[1] = {
    aa : 1
}
array[2] = {
    aa : 2
}
array[3] = {
    aa : 3
}
array[4] = {
    aa : 4
}
array[5] = {
    aa : 5
}
array[6] = {
    aa : 6
}
array[7] = {
    aa : 7
}
array[8] = {
    aa : 8
}


print(array); // before

for (var i = 0; i < array_length(array); ++i) {
    array_delete(array, i, 1);
}

print(array); // after

What happens:



Yes, I could use array = [], but that's not what I'm wanting to do.




What I want to do:

I have two arrays:
GML:
// array 1
array1[0] = {
    aa : 0
}
array1[1] = {
    aa : 1
}
array1[2] = {
    aa : 2
}
array1[3] = {
    aa : 3
}
array1[4] = {
    aa : 4
}
array1[5] = {
    aa : 5
}


// array 2
array2 = [1, 3, 4];
I want to delete all items from array1, however, keep in array1, the numbers (array index position) that are in array2 (1, 3, 4).

I'm making a game of questions and answers (quiz), and array2 is supposed to be a list of questions to be eliminated from the question array (array1).



What I tried:

GML:
for (var i = 0; i < array_length(array1); ++i) {
    for (var j = 0; j < array_length(array2); ++j) {
        if (i == array2[j]) break;
        array_delete(array1, i, 1);
    }
}
However this does not work because the array_delete() function is skipping the positions...


Does anyone have any other solution for this purpose or would you know how to solve it?
Any help is appreciated. Thank you very much!
 

Roldy

Member
Couple things:
  • Do it in reverse order for array1
    • You are currently doing it in increasing order then as you delete indices you change the relative index
  • Loop through all of array2 and set a set a doNotDeleteFlag
    • You are currently looping through array2 j times and potentially delete multiple times
GML:
for (var i = array_length(array1) - 1; i >= 0; i--) {  // Loop backwards
    var doNotDelete = false;
    for (var j = 0; j < array_length(array2); j++) {  // Check if any element of array2 == i
        if (i == array2[j]) {
            doNotDelete = true;
            break;
        }
    }
 
    if (!doNotDelete) {
        array_delete(array1, i, 1);
    }
 
}
 

FoxyOfJungle

Kazan Games
Loop backwards, not forwards when deleting from an array. Since deleting happens immediately, when you increment i you move to the next position in the array, but what was in that position has moved up one space because what was before it has been deleted.

See this for an example https://forum.yoyogames.com/index.php?threads/gml-joseki-series-for-block-recipe-cards.82306/
Couple things:
  • Do it in reverse order for array1
    • If you do it in increasing order then as you delete indices you change the relative index
  • Loop through all of array2 and set a set a doNotDeleteFlag
GML:
for (var i = array_length(array1) - 1; i >= 0; i--) {  // Loop backwards
    var doNotDelete = false;
    for (var j = 0; j < array_length(array2); j++) {  // Check if any element of array2 == i
        if (i == array2[j]) {
            doNotDelete = true;
            break;
        }
    }
 
    if (!doNotDelete) {
        array_delete(array1, i, 1);
    }
 
}
Wow!! I didn't know that I had to do the loop in reverse order. Thank you so much, it worked like a charm.
 

NightFrost

Member
This advice holds true to pretty much any indexed containers in any programming language when you're deleting entries. Forward-loop will cause you to skip entries that replace the deleted entries, reverse order doesn't as you've already processed the entries that "fall down" to occupy empty spaces. (You can visualize the process as going through stacked boxes to understand what the problem and solution are.)
 
Top