Problem with table.insert?

#1

Hey everyone!

Looks like I can’t figure out what’s wrong with that table. I’ve checked the forum, and found nothing helpful… seems like what I’m stumbled on is obvious to others.

I am generating a new table item on top of the table, and then I try to add something to that new item. But it seems like changes are being made to it’s first position.

local atable =
	{
		{ x = 0, y = 0}
	}
table.insert(atable, atable[1])
atable[table.maxn(atable)].x = 1
atable[table.maxn(atable)].y = 1

But in that case atable[1].x = 1 while it should be 0

1 Like

#2
table.insert(atable, atable[1])

Is adding the same entry once more, it does not do a copy, it will in fact just add a new reference to the previous one.

For example, to verify this you can try this:

print(atable[1] == atable[2])

which should print true, since they are the same table. :slight_smile:

Take a look at the output of this code.

You need to create some table-copy-function before you run table.insert with the new element. There are no built in function for this, since behaviour depends on what you actually want to do (for example, do you want sub tables to also be copied by value, aka deep copy, or should they be copied by reference?).

3 Likes

#3

Edit: Sven was too fast, but just to reiterate regarding the reference: You can see this clearly if you pprint the table:

{ --[[0x1104a3150]]
  1 = { --[[0x1104a31b0]]
    y = 1,
    x = 1
  },
  2 = { --[[0x1104a31b0]]
    y = 1,
    x = 1
  }
}

The first and second item have the same address and is thus the same object.

4 Likes

#4

Also, worth noting, from the Lua reference regarding table.maxn:

To do its job this function does a linear traversal of the whole table.

Which might be a performance issue depending on how big your table is. In your example you are actually traversing the table twice to get the same number. I’m not 100% sure but I think #atable should just return the size of the table (if it’s a regular “array”), but also store it in a temp variable so you don’t have to do it twice;

...
local atable_len = #atable
atable[atable_len].x = 1
atable[atable_len].y = 1
...
1 Like

#5

Thanks! Well… not sure how to create one without that table.insert thing. I’ll check that.

Actually, table.insert works perfectly in my code in some other function. Where whole table is exporting to a file, and then loading to a new table. Couldn’t think there will be a problem with that.

UPD: Oh, got it! Thanks! :grinning:

0 Likes

#6

If you are just working with positions, you can use vectors. The vmath.vector3() function will copy a vector if you give it another vector as the argument.

local pos1 = vmath.vector3(0, 0, 0)
local pos2 = vmath.vector3(pos1) -- `pos2` is now a different vector than pos1, but has the same coordinates.
pos2.x, pos2.y = 1, 1
1 Like

#7

There’s a bunch of data, but guess vectors would be better anyway, thanks! The table is dynamic with few dozen entities.

1 Like

#8

If you need to create a copy of a previous entry I would create a simple copy-function for this, here are some implementation alternatives: http://lua-users.org/wiki/CopyTable

In some cases it might make more sense to have a function to create a new “entry” instead, maybe passing in a previous entry and just copy some of the fields… I don’t know your exact use case, but for example one might do something like this;

function new_entry(x, y)
    local entry = {x = x,
                   y = y,
                   some_random_value = math.random(),
                   some_static_field = 42
    }
    return entry
end

...
-- and usage;
table.insert(atable, new_entry(12, 45))

-- or using x and y from a previous entry;
local prev_entry = atable[#atable]
table.insert(atable, new_entry(prev_entry.x, prev_entry.y))
3 Likes

#9

Yeap! Definitely works :grinning:
Local function seems like a really elegant way.

Not sure if table.insert was made that way on purpose. Thought I could make that pathfinding function in an hour, and it took me 2 days. =)

Thank you all once again!

3 Likes