can't remove an element from a table

hi - I’m trying to build a sudoku generator. I’m trying to remove an element from a table with the following code:

for j = (currentSquare + 1),9 do       for p=1,#sudoku[j] do         if (sudoku[j][p] == numberChosen) then         table.remove(sudoku[j],sudoku[j][p]) break end end

I am trying to remove the number “numberChosen” from the table.

What is going wrong here is that the element is being removed from position “numberChosen”, not from position [p]. So, for example, if I have the table

{1,3,4,6}

and “numberChosen” is 3, the value of p will be 2 but it removes the 4, i.e. not “numberChosen”, but the number at position “numberChosen”.

I am bewildered. What am i doing wrong?

thanks.

i figured it out - i should have written

      

 if (sudoku[j][p] == numberChosen) then         table.remove(sudoku[j],p) break end

stared at that one for a long time…

Just a suggestion, when looping through a table looking for items to remove I find it’s best to loop through it in reverse:

for p = #sudoku[j], 1, -1 do 

instead of 

for p=1,#sudoku[j] do

You’re example is ok because you have a “break” once you find the element to remove, but in some cases you might want to remove multiple elements in one pass.

Using table.remove will make the table length shorter so by the time you reach the end of the loop you’ll hit lots of nil keys or will miss some items completely. For example:

local myTable = {1, 1, 2, 1, 2, 3, 1, 2, 3} local numToRemove = 1 for i = 1, #myTable do if myTable[i] == numToRemove then table.remove(myTable, i) end end

The first entry will match the criteria, so myTable[1] will be removed, myTable[2] will then be moved down to myTable[1], [3] to [2] etc so that there are no gaps in the table.

The loop will then move on to check myTable[2], but because the element that was in myTable[2] is now in myTable[1] it will not be checked. The value being checked instead is the one that was formerly in myTable[3]. That mean that when the loop ends it will still have at least one element with the value 1.

Also, the loop will run 9 times because #myTable was 9 when the loop started. But because some elements have been removed and the table is now shorter, myTable[7] myTable[8] and myTable[9] will all be nil.

You may already know this, but I just thought I’d point it out  :slight_smile:

thanks, that’s helpful. 

 

 

i figured it out - i should have written

      

 if (sudoku[j][p] == numberChosen) then         table.remove(sudoku[j],p) break end

stared at that one for a long time…

Just a suggestion, when looping through a table looking for items to remove I find it’s best to loop through it in reverse:

for p = #sudoku[j], 1, -1 do 

instead of 

for p=1,#sudoku[j] do

You’re example is ok because you have a “break” once you find the element to remove, but in some cases you might want to remove multiple elements in one pass.

Using table.remove will make the table length shorter so by the time you reach the end of the loop you’ll hit lots of nil keys or will miss some items completely. For example:

local myTable = {1, 1, 2, 1, 2, 3, 1, 2, 3} local numToRemove = 1 for i = 1, #myTable do if myTable[i] == numToRemove then table.remove(myTable, i) end end

The first entry will match the criteria, so myTable[1] will be removed, myTable[2] will then be moved down to myTable[1], [3] to [2] etc so that there are no gaps in the table.

The loop will then move on to check myTable[2], but because the element that was in myTable[2] is now in myTable[1] it will not be checked. The value being checked instead is the one that was formerly in myTable[3]. That mean that when the loop ends it will still have at least one element with the value 1.

Also, the loop will run 9 times because #myTable was 9 when the loop started. But because some elements have been removed and the table is now shorter, myTable[7] myTable[8] and myTable[9] will all be nil.

You may already know this, but I just thought I’d point it out  :slight_smile:

thanks, that’s helpful.