This question already has an answer here:
lua: iterate through all pairs in table
(1 answer)
Closed 8 years ago.
I am trying to initialize and print a table. It just isnt working. Any idea what is wrong with this code?
--!/usr/bin/env lua
local retv = {}
retv["test"] = 1000
for k,v in ipairs(retv) do
print (k,v)
end
It prints nothing. I am sure I am missing something very basic but I cant figure this out.
There are two forms of the for-loop in Lua:
The numeric and the generic for-loop.
ipairs(t) is an iterator constructor returning up to three arguments suitable for the generic for, allowing you to iterate over the initial sequence (indices 1,2,3,...) in order.
Possible implementations:
function ipairs(t)
local i = 0
return function()
i = i + 1
if t[i] ~= nil then
return i, t[i]
end
end
end
local function ipairs_helper(t, i)
i = i + 1
if t[i] ~= nil then
return i, t[i]
end
end
function ipairs(t)
return ipairs_helper, t, 0
end
As you can see, that will never return your entry with key "test".
What you want instead, is pairs(t), which is equivalent to next, t.
That will iterate all elements.
You need to use pairs instead of ipairs. pairs iterates over all keys, ipairs only iterates over keys that form a sequence of integers starting from 1 without gaps. (Whether these keys are stored in the array or the hash part of the table is an implementation detail and may change during the lifetime of the table.)
For example, ipairs({'a', 'b', nil, 'c'}) iterates over keys 1 and 2, stopping at (and not including) 3, as that key is missing from the table.
Related
I want to create a 0-memory lua array that actually jumps to my custom function when I use operators like # [] on it
Any ideas on how to do this?
I want the user using this fake array to not perceive it as fake, it is worse than a normal array in terms of access speed, but has better memory performance
Lua implements something called metamethods (documentation)
Metamethods are functions which exist subsequently to a table and fire on certain operations such as indexing the array, reading missing indices, gathering the length of the array, or even math operations such as + - * /
-- Start by creating your array, and another for demonstration purposes
local object = {}
local demo = {1, 2, 3, 4}
-- Create a your metamethods contained in a table
local metamethods = {
__index = function(self, index) return demo[index] end;
__newindex = function(self, index, value) demo[index] = value end;
}
-- Lets print out what is in the object table for demonstration
print(object[1]) -- nil
print(object[2]) -- nil
print(object[3]) -- nil
print(object[4]) -- nil
-- Use the setmetatable(table a, table b) function to set the metamethods
-- stored in 'b' to 'a'
setmetatable(object, metamethods);
-- Lets print out what is in the object table for demonstration
print(object[1]) -- 1
print(object[2]) -- 2
print(object[3]) -- 3
print(object[4]) -- 4
Why does the above code work? When a metatable is set with the index __index (metamethods.__index), if the attached table's (object) is indexed and the key isn't present (nil), then it will call the specified function. In the __index function, it returns the demo's table with the index passed straight to it. So its as if: when you do object[1], you actually do demo[1] but with a metamethod's help of course. This effectively creates a proxy of sorts.
One cool and quick usage of setmetatable() is that it returns the value you pass as the first parameter (a table).
local object1 = setmetatable({}, { __index = function(self, i) return 1 end })
print(object1["a"]) -- 1
print(object2[321]) -- 1
I have gone through many questions and Google results but couldn't find the solution.
I am trying to sort a table using table.sort function in Lua but I can't figure out how to use it.
I have a table that has keys as random numeric values. I want to sort them in ascending order. I have gone through the Lua wiki page also but table.sort only works with the table values.
t = { [223]="asd", [23]="fgh", [543]="hjk", [7]="qwe" }
I want it like:
t = { [7]="qwe", [23]="fgh", [223]="asd", [543]="hjk" }
You cannot set the order in which the elements are retrieved from the hash (which is what your table is) using pairs. You need to get the keys from that table, sort the keys as its own table, and then use those sorted keys to retrieve the values from your original table:
local t = { [223]="asd", [23]="fgh", [543]="hjk", [7]="qwe" }
local tkeys = {}
-- populate the table that holds the keys
for k in pairs(t) do table.insert(tkeys, k) end
-- sort the keys
table.sort(tkeys)
-- use the keys to retrieve the values in the sorted order
for _, k in ipairs(tkeys) do print(k, t[k]) end
This will print
7 qwe
23 fgh
223 asd
543 hjk
Another option would be to provide your own iterator instead of pairs to iterate the table in the order you need, but the sorting of the keys may be simple enough for your needs.
What was said by #lhf is true, your lua table holds its contents in whatever order the implementation finds feasible. However, if you want to print (or iterate over it) in a sorted manner, it is possible (so you can compare it element by element). To achieve this, you can do it in the following way
for key, value in orderedPairs(mytable) do
print(string.format("%s:%s", key, value))
end
Unfortunately, orderedPairs is not provided as a part of lua, you can copy the implementation from here though.
The Lua sort docs provide a good solution
local function pairsByKeys (t, f)
local a = {}
for n in pairs(t) do table.insert(a, n) end
table.sort(a, f)
local i = 0 -- iterator variable
local iter = function () -- iterator function
i = i + 1
if a[i] == nil then return nil
else return a[i], t[a[i]]
end
end
return iter
end
Then you traverse the sorted structure
local t = { b=1, a=2, z=55, c=0, qa=53, x=8, d=7 }
for key,value in pairsByKeys(t) do
print(" " .. tostring(key) .. "=" .. tostring(value))
end
There is no notion of order in Lua tables: they are just sets of key-value pairs.
The two tables below have exactly the same contents because they contain exactly the same pairs:
t = { [223] = "asd" ,[23] = "fgh",[543]="hjk",[7]="qwe"}
t = {[7]="qwe",[23] = "fgh",[223] = "asd" ,[543]="hjk"}
Ive been coding for a mod Im making for a game but I ran into an issue with tables not returning values when the key is entered:
for k, v in pairs(self.math) do
print(self.exce[1])
print(self.exce[k])
print(k)
if self.exce[k] ~= nil then
self.math[k] = nil
end
end
This is the specific part of the script that is breaking. When I run these in the game it returns:
[lua]: true
[lua]: nil
[lua]: 1
Which means is basically saying that 1 is not equal to 1.
The function I used to store my data is
function filterExceptions.server_onException( self, id )
if self.exce[id] == nil then
self.exce[id] = true
self.network:sendToClients( "client_onList", id )
else
self.exce[id] = true
self.network:sendToClients( "client_offList", id )
end
end
In this code the self is a table made by the game you can acces and get game data from or store it in and the id comes from a function I made to get the players id. This id in this case is a 1 (I printed it multiple times).I know that every part of this code is working except for the code in the first block, and escpecialy the part where it tries to do self.exce[k]. Ive tried a lot like going trough every variable in self.exce to see if it was in there and then do stuff, but it still wouldn't work. Its very annoying how lua thinks that k ~= 1 while it definitely is, ive even used similar code in a part that is working.
So what is wrong about this code that its not printing the self.exce[k] while self.exce[1] does work? Dont worry about the creation of the table and stuff, cuz that is already happening whenever it is needed, else it would have given errors about that too.
Putting together a couple different comments and your code here, it looks like the index value of the array in some particular iteration of the "for in pairs" loop (or perhaps all of them, but I'll touch on that in a minute) is a string instead of an integer.
To summarize if you don't want to read the entire thing, "for k, v in pairs" loops will iterate through an entire array, setting k to the index of the value v. It appears your "for in pairs" loop is attempting to iterate through a value of nil where k is a string instead of an integer. You may also want to look into using ipairs instead of pairs in your for loop.
The value of someArray[1]is different than the value of someArray["1"].
The index [1] is a completely different index than the index ["1"] for any given array.
A simple fix would be to use
ind = tonumber(k)
print(self.exce[ind])
This converts the string k to a number type. Be aware this may throw an error if k is a non-numerical string. If the array has any values where the index is a non-numerical string, you may get an error. As the other answer suggests, converting the index k to a string instead of an integer would work as well, and would not throw errors if you used a non-numerical value for your indices.
My guess as to why this is happening would be that the function that you're using to store your data to an array, filterExceptions.server_onException( self, id ), is being passed a string instead of an integer, which would result in the k value being set to a string in that particular iteration of the "for in pairs" loop.
To help better understand this, here's a bit of example code:
a = {true, false, false}
a[1] = true
a["1"] = true
print("Raw for in pairs loop")
for k, v in pairs (a) do
print(type(k)..k)
end
print("For in pairs converting k to a number")
for k, v in pairs (a) do
ind = tonumber(k)
print(type(ind)..ind)
end
print("For in ipairs")
--which I'm not sure I completely understand but
--it seems to skip over any iteration where k is not a number
for k, v in ipairs(a) do
print(type(k)..k)
end
This code produces the following output:
Raw for in pairs loop
number1
number2
number3
string1
For in pairs converting k to a number
number1
number2
number3
number1
For in ipairs
number1
number2
number3
EDIT: Not sure what's going on in the self.math table so I can't comment on that.
EDIT2: I'd also refer you to the following link: lua: iterate through all pairs in table
The top answer there should help understand the difference between pairs and ipairs, if you don't already. You may want to use ipairs to prevent values of k where v == nil from being iterated through with pairs. pairs will iterate through every key/value pair, whereas ipairs will iterate through integer keys starting at 1 and going until it hits a nil value.
EDIT3: I'm sorry this is such a long answer...I just wanted to be thorough.
It apears converting the id to a string fixes this, tough im still confused as to why this same code worked on another block and not this one.
function filterExceptions.server_onException( self, id )
local id2 = tostring(id)
if self.exce[id2] == nil then
self.exce[id2] = true
self.network:sendToClients( "client_onList", id )
else
self.exce[id2] = true
self.network:sendToClients( "client_offList", id )
end
end
I am stuck trying to make the contese of a table (all integers) add together to form one sum. I am working on a project where the end goal is a percentage. I am putting the various quantities and storing them in one table. I want to then add all of those integers in the table together to get a sum. I haven't been able to find anything in the standard Library, so I have been tyring to use this:
function sum(t)
local sum = 0
for k,v in pairs(t) do
sum = sum + v
end
return sum
However, its not giving me anything after return sum.... Any and all help would be greatly appreciated.
A more generic solution to this problem of reducing the contents of a table (in this case by summing the elements) is outlined in this answer (warning: no type checking in code sketch).
If your function is not returning at all, it is probably because you are missing an end statement in the function definition.
If your function is returning zero, it is possible that there is a problem with the table you are passing as an argument. In other words, the parameter t may be nil or an empty table. In that case, the function would return zero, the value to which your local sum is initialized.
If you add print (k,v) in the loop for debugging, you can determine whether the function has anything to add. So I would try:
local function sum ( t ) do
print( "t", t ) -- for debugging: should not be nil
local s = 0
for k,v in pairs( t ) do
print(k,v) --for debugging
s = s + v
end
return s
end
local myTestData = { 1, 2, 4, 9 }
print( sum( myTestData) )
The expected output when running this code is
t table: [some index]
1 1
2 2
3 4
4 9
16
Notice that I've changed the variable name inside the function from sum to s. It's preferable not to use the function name sum as the variable holding the sum in the function definition. The local sum in the function overrides the global one, so for example, you couldn't call sum() recursively (i.e. call sum() in the definition of sum()).
Given a table with mixed indexes like:
table = {
foo = 'bar'
[1] = 'foobar'
}
My question is about the # which gives the last index which is not separate through a gap while iterating through the table.
print(#table)
will give the output 1.
table = {
foo = 'bar',
lol = 'rofl',
[1] = 'some',
[2] = 'thing',
[3] = 'anything',
[4] = 'else'
}
print(#table)
should print 4
Can I be 100% sure that the # will never be distracted by non-numeral indexes?
Are those indexes really unregarded at every time?
Yes, you can count on that (in lua 5.1).
From the lua reference manual:
The length operator is denoted by the unary operator #. The length of
a string is its number of bytes (that is, the usual meaning of string
length when each character is one byte).
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 the
array has "holes" (that is, nil values between other non-nil values),
then #t can be any of the indices that directly precedes a nil value
(that is, it may consider any such nil value as the end of the array).
lua 5.2 allows for the __len metamethod to operate on tables and that means # can do other things. See #kikito's answer for some examples.
Etan answer is correct, but not complete.
In Lua, if a table's metatable has a __len function, it will control what the # operator spits out. One can define it so that it takes into account the non-array keys.
local mt = {__len = function(tbl)
local len = 0
for _ in pairs(tbl) do len = len + 1 end
return len
end}
This demonstrates the thing:
local t = {1,2,3,4,foo='bar',baz='qux'}
print(#t) -- 4
setmetatable(t, mt)
print(#t) -- 6
If you really want to make sure that you get the "proper" array-like length, you must use rawlen instead:
print(rawlen(t)) -- 4, even with the metatable set
Edit: Note that __len does not work as I mention on Lua 5.1
The only way is to iterate through entries and count them. Iterate with ipair through the item and increment counter then return result.
function tablelength(T)
local count = 0 for _ in pairs(T) do
count = count + 1 end
return count
end
The # operator only work for hash table type.
See: How to get number of entries in a Lua table?