Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
COMMUNITY QUESTION

Why will a Table's children not remove properly when looped through?

So the script I have is:

local cards = {{"a"},{"b"},{"c"},{"d"},{"e"},{"f"},{"g"}}
for i = 1,#cards + 1 do
	if cards == 0 then
		print"done"
	else
		local card = cards[math.random(#cards)]
		print(card[1])
		table.remove(cards,cards[card])
	end
	wait(.1)
end

What I believe this should do, when looping through the table, is find a child at random, print its content(s), and then remove it. When there are no more contents in the table left, it will print "done". When running the script, however, the output randomly prints:

f
c
e
c
a
a
a

and running it a second time:

f
c
b
a
b
a
a

even though supposedly removed from the table, the child somehow is repeated again in the script when looping through it another time (a,b and c for an example). for what I am doing the children of the table have to be other tables, so I can't change that. So what is wrong here? If you have a question for clarification please comment, All answers appreciated, thank you. ~Xduel

2 comments

0

Why do you need separate tables? It would be SO much cleaner and simpler to just put it in one table.

0

They would be holding other contents in them, for example cards = {{"a",2},{"b",4}{"c",6} ect.} in my case every table in the table must 4 place holders for 4 different values.

3 answers

There are a few typos here.

for i = 1,#cards  do
    if #cards == 0 then

Nonetheless, this check is a bit confusing (I'm unsure whether or not it's wrong -- Lua for loops can act strangely), so it would be better to have a variable for the loop:

local number = #cards
for i = 1, number do
	if #cards == 0 then

Now, look to your use of table.remove:

local card = cards[math.random(#cards)]
print(card[1],card,cards[card] )
table.remove(cards,cards[card])

I have added to the print statement. We get an output that looks like this:

f	table: 0x1300110	nil
c	table: 0x1305480	nil
d	table: 0x13054d0	nil
d	table: 0x13054d0	nil
c	table: 0x1305480	nil
a	table: 0x1302400	nil
a	table: 0x1302400	nil

Remember, card is not the position of the card you want, but the card itself. So cards[card] is actually nothing in particular.

Relatedly, table.remove requires a position of an element, not the element itself, to remove.

Usually, passing a non-number value to table.remove would cause an error. But when you don't specify a second parameter to table.remove, it just deletes the last element in the list.

That is what is happening here (it's a tiny "gotcha" that I actually just learned about because of this question)


To fix this,

local card = math.random(1, #cards)
print( cards[card][1] )
table.remove(cards, card)



Notational Aside: The things in a table are not its children (that term is reserved for hierarchical structures, like trees)

Usually they would be called items, table items, list items, or elements.

1 comment

1

This is clever, thank you very much!

You're removing the last card in the list, not the math.random one

1 comment

0

Why is it removing the last card on the list, and how? From what I read, when removing, it goes into the cards table and removes the card with the same key as the math.random one, therefore removing it..?

(For some reason, I can't comment on that post)

When you call math.random, you can give one or two numbers. Example:

print(math.random(1,5)) --prints any number between 1 and 5, including 1 and 5
print(math.random(5)) --prints any number after 5, including 5

You put

card = cards(math.random(#cards))
table.remove(cards, cards[card])

The table has 7 items in it. Basically, you told it to, instead of removing anything in the table with a position between 1 and 7, to remove anything in the table with a position of 7 or more. If you put

card = cards(math.random(1, #cards))
table.remove(cards, cards[card])

instead, it would have removed anything with a position between 1 and 7. I know it's confusing, but try to understand. This was incredibly hard to put into words.

3 comments

1

This is incorrect. Quote from the wiki: "If only the first argument, m is passed, it returns an integer between 1 and m."

0

No. I did a CTRL+F on the math.random wiki page, and it had no quotes like that.

This discussion is preserved as it was. New answers, comments, and votes are closed.