Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
0

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

Asked by
Xduel 211 Moderation Voter
10 years ago

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

0
Why do you need separate tables? It would be SO much cleaner and simpler to just put it in one table. Perci1 4988 — 10y
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. Xduel 211 — 10y

3 answers

Log in to vote
3
Answered by
BlueTaslem 18071 Moderation Voter Administrator Community Moderator Super Administrator
10 years ago

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
This is clever, thank you very much! Xduel 211 — 10y
Ad
Log in to vote
-1
Answered by 10 years ago

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

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..? Xduel 211 — 10y
Log in to vote
-1
Answered by 10 years ago

(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.

1
This is incorrect. Quote from the wiki: "If only the first argument, m is passed, it returns an integer between 1 and m." Perci1 4988 — 10y
0
No. I did a CTRL+F on the math.random wiki page, and it had no quotes like that. bobafett3544 198 — 10y

Answer this question