table.insert -> remember key of inserted value - lua

I'm inserting the value of an variable to a table and want to make sure the action succeeded.
Therefore I want to return the value, but not by the var, but from the table.
Is there a more simple way as iterating trough the table again?
Some way to remember the key of the value in the table, while it's inserted?
function(value)
for _,v in pairs(theTable) do
if v == value then
return --(due the table already contains the value)
end
end
table.insert(theTable, value)
return -- table.[VALUE]
end

local ix = #theTable + 1
theTable[ix] = value
That's pretty much what table.insert is doing:
As a special (and frequent) case, if we call insert without a position, it inserts the element in the last position of the array (and, therefore, moves no elements)
As a sidenote, your function is pretty inefficient; you're doing an O(n) "contains" check, which could be made much better if you created an index of values.

Related

Lua how do you retrieve a table row by a table value?

Example:
mytable = {{id=100,wordform="One Hundread"},{id=200,wordform="Two Hundread"}}
I want to be able to access the row based on the id to do something like this:
mynum = 100
print ("The value is " .. mytable[mynum].wordform)
The main point here is I want to be able to set the index value so I can predictably retrieve the associated value later as I might do with a java hashmap.
Ideally your table should just use the ID as key:
local mytable = {[100] = {wordform = "One hundred"}, [200] = {wordform = "Two hundred"}}
print("The value is " .. mytable[100].wordform)
If your table is in list form, you can convert it to ID form rather easily:
local mytable_by_id = {}
for _, item in pairs(mytable) do mytable_by_id[item.id] = item end
Using the hash part of a Lua table is definitely preferable over looping over the list entries in linear time as Renshaw's answer suggests (the fact that it's hidden behind a metatable may hide the poor performance and trick the reader into believing a hash indexing operation is taking place here though).
Furthermore, that answer won't even work correctly, as the list part uses integer keys as well; IDs that are valid list part indices would possibly return the wrong element. You'd have to use a function instead of a metatable.
you can use metatable
setmetatable(mytable, {__index = function(tbl, id)
for _, item in pairs(tbl) do
if type(item) == "table" and item.id == id then
return item
end
end
end})
then
mynum = 100
print ("The value is " .. mytable[mynum].wordform) -- The value is One Hundread

remove all entries with specified value in table

I want to delete all entries from a table, wich equals a given value.
Now, I got a pretty little problem one might to know, how to handle.
This is the Code:
function(list_to_search_in, compared_value, invert)
for k,v in pairs(list_to_search_in) do
if invert and v ~= compared_value then
table.remove(list_to_search_in, v)
if not invert and v == compared_value then
table.remove(list_to_search_in, v)
end
end
end
The Problem:
Let's say the table is { 1, 2, 3, 2 }. So when I'm iterating through that loop and come to the first match, it's removed from the table. This means the value and the key is deleted.
Now the key of the deleten value is assigned to the next value in line. But due the skript will check the value of the next key, this value (whichs kay has been just altered) will never be checked.
I thought, a simple
k = k - 1
after a remove would do the job, but it doesn't.
v = nil
would do great I think, but only if garbage-collector does not do his job in this very moment the pairs iterates to the next value.
Anyone has an idea? I would prefer an text-based hint to a finished syntax which solves the problem.
Don't use table.remove for this. It squeezes the "hole" out of array-like tables. That's not allowed during an iteration using pairs/next. Just set the value to nil.
If you need to squeeze holes out of the table then you can either create a new table and populate it with only the values you want to keep or do the removals during the first pass and then squeeze out holes in a second pass.
Also the order of item traversal when using pairs is not guaranteed in any way.

Lua table continues to be empty, even though I am giving it stuff

In my Lua-powered game, I am trying to create an Explorer to see all the instances that have been created. I've created a function inside my DataModel "class" (as I like to call it) that will scan the children of an item, and put it neatly inside a table.
function DataModel.ObjectToTable(obj)
children = {}
for i,v in pairs(obj:GetChildren()) do
table.insert(children, DataModel.ObjectToTable(v))
end
print(obj.Name)
dmyself = {}
dmyself.Name = obj.Name
dmyself.Object = obj
dmyself.Children = children
print(#dmyself)
return dmyself
end
The issue is that, the print(#dmyself) is coming out as 0. But as you can see, I just set 3 things inside of it. What could cause such a thing to happen? Am I doing something obviously wrong?
The print(obj.Name) line is returning what it should. I am simply stuck on 'dmyself'.
# is the length of the array part of the Lua table; it only takes integer keys into account. More specifically,
The length of a table t is defined to be any integer index n such that t[n] is not nil and t[n+1] is nil; moreover, if t[1] is nil, n can be zero. For a regular array, with non-nil values from 1 to a given n, its length is exactly that n, the index of its last value.
If you use pairs, you can see that your table is not empty. But since there's nothing in the array part of the table, it's length is zero.

How to check if a table contains an element in Lua?

Is there a method for checking if a table contains a value ? I have my own (naive) function, but I was wondering if something "official" exists for that ? Or something more efficient...
function table.contains(table, element)
for _, value in pairs(table) do
if value == element then
return true
end
end
return false
end
By the way, the main reason I'm using this functions is to use tables as sets, ie with no duplicate elements. Is there something else I could use ?
You can put the values as the table's keys. For example:
function addToSet(set, key)
set[key] = true
end
function removeFromSet(set, key)
set[key] = nil
end
function setContains(set, key)
return set[key] ~= nil
end
There's a more fully-featured example here.
Given your representation, your function is as efficient as can be done. Of course, as noted by others (and as practiced in languages older than Lua), the solution to your real problem is to change representation. When you have tables and you want sets, you turn tables into sets by using the set element as the key and true as the value. +1 to interjay.
I know this is an old post, but I wanted to add something for posterity.
The simple way of handling the issue that you have is to make another table, of value to key.
ie. you have 2 tables that have the same value, one pointing one direction, one pointing the other.
function addValue(key, value)
if (value == nil) then
removeKey(key)
return
end
_primaryTable[key] = value
_secodaryTable[value] = key
end
function removeKey(key)
local value = _primaryTable[key]
if (value == nil) then
return
end
_primaryTable[key] = nil
_secondaryTable[value] = nil
end
function getValue(key)
return _primaryTable[key]
end
function containsValue(value)
return _secondaryTable[value] ~= nil
end
You can then query the new table to see if it has the key 'element'. This prevents the need to iterate through every value of the other table.
If it turns out that you can't actually use the 'element' as a key, because it's not a string for example, then add a checksum or tostring on it for example, and then use that as the key.
Why do you want to do this? If your tables are very large, the amount of time to iterate through every element will be significant, preventing you from doing it very often. The additional memory overhead will be relatively small, as it will be storing 2 pointers to the same object, rather than 2 copies of the same object.
If your tables are very small, then it will matter much less, infact it may even be faster to iterate than to have another map lookup.
The wording of the question however strongly suggests that you have a large number of items to deal with.
I can't think of another way to compare values, but if you use the element of the set as the key, you can set the value to anything other than nil. Then you get fast lookups without having to search the entire table.
-- in some helper module
function utils_Set(list)
local set = {}
for _, l in ipairs(list) do set[l] = true end
return set
end
-- your table here
long_table = { "v1", "v2", "v1000"}
-- Consult some value
_set = utils_Set(long_table)
if _set["v1"] then print("yes!") end

Getting table entry index

I can't get table entry index. I need it to remove an item from table.
I use table.insert to add entries to table.
Another question: why Lua doesn't have "overload" to function table.remove so one can remove item by associative index?
Tables implement an unordered one to many relation between keys and values. In other words, any particular key (index) can only appear once in a table, but a value can appear multiple times.
If you know the key k, then t[k] = nil will remove both the key and the associated value from the table. However, this operation has no effect on any other keys or values in the table.
The table.insert and table.remove functions operate over the set of sequential integer keys beginning at 1, that are used by convention to implement arrays or lists. For that purpose, they manipulate other values in the list so as to keep the list from developing holes.
One way to find a key at which some value is found is to simply search the table. If this will be done more than once, then it is probably a good idea to build a second table that inverts the key/value pairs so that lookup by value is as fast as lookup by index.
A suitable implementation will depend on your assumptions and needs. Some samples are:
-- return the first integer index holding the value
function AnIndexOf(t,val)
for k,v in ipairs(t) do
if v == val then return k end
end
end
-- return any key holding the value
function AKeyOf(t,val)
for k,v in pairs(t) do
if v == val then return k end
end
end
-- return all keys holding the value
function AllKeysOf(t,val)
local s={}
for k,v in pairs(t) do
if v == val then s[#s+1] = k end
end
return s
end
-- invert a table so that each value is the key holding one key to that value
-- in the original table.
function Invert(t)
local i={}
for k,v in pairs(t) do
i[v] = k
end
return i
end
t[k]=nil removes from t the entry with key k.
For the second question, the answer is that tables can have individual metatables.

Resources