Why isn't my LUA interpreter able to handle string key values? - lua

When testing code with both a predefined script and the LUA runtime environment, LUA will not take any form of string key values. However, if a numerical value key is used LUA will work with it as intended. The exception to this rule when I am using Tshark with a LUA file to parse packet captures. This allows the string key value syntax to work normally. Is there something I may be performing wrong?
I have tried creating several .lua script files with different variations including:
testArray.NewItem = "value1"
testArray["NewItem"] = "value1"
NewItemValue = "NewItem"
testArray[NewItemValue] = "value1"
These all result in an nil value or an error due to trying to call a nil value depending on the return style used to check.
> tcpstream = {}
> stream1 = tostring(14356)
> tcpstream[stream1] = "nothing"
> print(#tcpstream)
0
> print(tcpstream[1])
nil
> tcpstream[1] = "nothing"
> print(#tcpstream)
1
> print(tcpstream[1])
nothing
the output of the print(#tcpstream) after the tcpstream[stream1] = "nothing" should show 1 not zero. The subsequent print(tcpstream[1]) should also show "nothing".

From http://lua-users.org/wiki/TablesTutorial
The # operator doesn't count all the items in the table (!). Instead it finds the last integer (non-fractional number) key. Because of how it's implemented its results are undefined if all the integer keys in the table aren't consecutive. Which is why it shouldn't be used for tables used as sparse arrays[2]).
The '#' is not a good(sometimes not correct) way to count the number of elements in Lua table.
As for
> stream1 = tostring(14356)
> tcpstream[stream1] = "nothing"
> print(#tcpstream)
0
> print(tcpstream[1])
nil
Lua uses key,value pairs, not explicitly index. If you do 'arr[1] = 22', it means the value for the key '1' is 22, not the value for the first element is 22.

The length operator(#) does not work as you believe, this is a common mistake for beginners in Lua.
The default behavior for #sometable is to return the number of consecutive key starting at the number 1(or after any nil value for 5.3). String keys are never evaluated with the default # operator for a table.
In 5.3 if your sequence contains multiple nil values the behavior of # is non-deterministic.
Lua 5.3 Reference Manual: 3.4.7 – The Length Operator
Lua 5.1 Reference Manual: 2.5.5 – The Length Operator
I will include the lines from 5.1 as i feel it covers the information regarding the operator and tables well. While note identical to how 5.3 work it maybe easier to understand why you see the behavior you do.
2.5.5 – The Length Operator
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 t1 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).
Here are some examples of different table and their # results:
table1 = { --number keys in array
true,
true,
true,
}
table2 = { -- number keys in hash
[1] = true,
[2] = true,
[3] = true,
}
table3 = { -- only strings as key
['1'] = true,
['2'] = true,
['3'] = true,
}
table4 = { -- No key 2 defined
[1] = true,
-- [2] = true,
[3] = true,
}
table5 = { -- table with both string and number keys
[1] = true,
['2'] = true,
}
print(#table1) -- 3
print(#table2) -- 3
print(#table3) -- 0
print(#table4) -- v5.3(1 or 3) v5.1(1)
print(#table5) -- 1

Related

How to order a Table to tables based on 1 single data part of it?

I am a hobbyest making mods in TableTop Simulator using LUA and have a question that I can not seam to work out.
I have a number of "objects" which is a table in TTS that contains various data for those objects. For example.. obj.position = {x,y,z}... and can be accessed at the axis level as well.
obj.position = {5,10,15} -- x,y,z
obj.position.x == 5
This is an example. The makers of TTS have made it so you can access all the parts like that. So I can acess the object.. and then its various parts. There is a heap, like name, mesh, difuse and a ton more. roations{x,y,z} etc etc
Anyway. I have a table of objects... and would like to order those objects based on the positional data of the x axis.. so highest to lowest. So if I have a table and obj1 in that table is x=3 and obj2 is x=1 and obj3 = x=2 it would be sorted as obj2,obj3,obj1
Pseudo code:
tableOfObjects = {obj1,obj2,obj3}
--[[
tableOfObjectsp[1] == obj1
tableOfObjectsp[2] == obj2
tableOfObjectsp[3] == obj3
tableOfObjectsp[1].position.x == 3
tableOfObjectsp[2].position.x == 1
tableOfObjectsp[4].position.x == 2
--]]
---After Sort it would look this list
tableOfObjects = {obj1,obj3,obj2}
--[[
tableOfObjectsp[1] == obj1
tableOfObjectsp[2] == obj3
tableOfObjectsp[3] == obj2
tableOfObjectsp[1].position.x == 3
tableOfObjectsp[2].position.x == 2
tableOfObjectsp[3].position.x == 1
--]]
I hope I am making sense. I am self taught in the last few months!
So basically I have a table of objects and want to sort the objects in that table based on a single value attached to each individual object in the table. In this case the obj.position.x
Thanks!
You need table.sort. The first argument is the table to sort, the second is a function to compare items.
Example:
t = {
{str = 42, dex = 10, wis = 100},
{str = 18, dex = 30, wis = 5}
}
table.sort(t, function (k1, k2)
return k1.str < k2.str
end)
This article has more information
table.sort(tableOfObjects, function(a, b) return a.position.x > b.position.x end)
This line will sort your table tableOfObjects in descending order by the x-coordinate.
To reverse order, replace > by <.
From the Lua reference manual:
table.sort (list [, comp])
Sorts list elements in a given order, in-place, from list[1] to
list[#list]. If comp is given, then it must be a function that
receives two list elements and returns true when the first element
must come before the second in the final order (so that, after the
sort, i < j implies not comp(list[j],list[i])). If comp is not given,
then the standard Lua operator < is used instead.
Note that the comp function must define a strict partial order over
the elements in the list; that is, it must be asymmetric and
transitive. Otherwise, no valid sort may be possible.
The sort algorithm is not stable: elements considered equal by the
given order may have their relative positions changed by the sort.
So in other words table.sort will sort a table in ascending order by its values.
If you want to order descending or by something other than the table value (like the x-coordinate of your table value's position in your case) you have to provide a function that tells Lua which element will come first.
you can create a function that handles this exact thing:
local function fix_table(t)
local x_data = {};
local inds = {};
local rt = {};
for i = 1, #t do
x_data[#x_data + 1] = t[i].position.x;
inds[t[i].position.x] = t[i];
end
local min_index = math.min(table.unpack(x_data));
local max_index = math.max(table.unpack(x_data));
for i = min_index, max_index do
if inds[i] ~= nil then
rt[#rt + 1] = inds[i];
end
end
return rt;
end
local mytable = {obj1, obj2, obj3};
mytable = fix_table(mytable);
fix_table first takes in every x value inside of the given table, and also places a new index inside the table inds according to each x value (so that they will be ordered from least to greatest), then it gets the smallest value in the x_data array table, which is used to traverse the inds table in order. fix_table checks to make sure that inds[i] is not equal to nil before it increases the size of the return table rt so that every value in rt is ordered from greatest to least, starting at index 1, and ending at index #rt, finally rt is returned.
I hope this helped.

how to represent nil in a table

Let's suppose I want to store a list of element. Including some nil values. The position of the values is significant, and I need to represent the absence of a value in the list at a given position.
Here is a problem:
a = {1,2,3,nil,4}
for k,v in ipairs(a) do
print(k,v)
end
print(a[4])
print(a[5])
The for loop will only print elements 1,2 and 3. It stops at nil. The first print statement prints nil, but I'm not sure if it is actually stored in the table or not. (Who knows?) The second print statement prints 4 - as expected.
So here is the question: how to represent a list of elements in a table, and iterate through them efficiently? Given the conditions above, e.g. the position is significant, and some of the positions are "empty". In other words: have no value, but the absence of that value at that position has a meaning.
This is module "null.lua"
local function null(...)
local t, n = {...}, select('#', ...)
for k = 1, n do
local v = t[k]
if v == null then t[k] = nil
elseif v == nil then t[k] = null
end
end
return (table.unpack or unpack)(t, 1, n)
end
_G.null = null
Use null() as encoder and decoder
require("null")
a = {null(1,2,3,nil,4)}
-- the same could be done element-by-element
-- a = {null(1),null(2),null(3),null(nil),null(4)}
for k,v in ipairs(a) do
v = null(v)
print(k,v)
end
print(null(a[4]))
print(null(a[5]))
Lua tables can be used to create any Abstract Data Structure, in your case you indicated that you want a "list". A Lua table is a data structure that combines numeric index based access with key:value access.
Based on your example, you are using the numeric index feature of tables that let you iterate (with ipairs()) through those values. You will not be able to put nil into the table since the numeric index stops at the first nil entry. The remaining values in the table are stored as key:value pairs.
There are several work-arounds, but it depends on why you want a nil in the list. The simplest approach is to use the string "nil" rather than the native data type nil.
a = {1, 2, 3, "nil", 4}
for k,v in ipairs(a) do
print(k,v)
end
The result of this code is:
1 1
2 2
3 3
4 nil
5 4
Because of the way Lua implements strings, there is not a performance penalty for comparing to the string "nil" versus comparing to the native type nil.
The issue of "holes" (caused by nil) in an array are discussed in Programming in Lua, Chapter 5 Tables. Roberto Ierusalimschy recommendation is to track the size of the array to avoid problems with holes.
The following code shows an Object Oriented approach to tracking the size of the list. There are many possible variations on this theme.
function makeList(...)
local list = table.pack(...)
list.length =
function(self) return self.n
end
list.append =
function(self, value)
self.n = self.n + 1
self[self.n] = value
end
list.print =
function(self)
for i = 1, self.n do print(i, self[i]) end
end
return list
end
a = makeList(1, 2, 3, nil, 4)
a:append(5)
a:print()
print(a:length())
The result is:
1 1
2 2
3 3
4 nil
5 4
6 5
6
Note that the function table.pack creates a field 'n' which contains the correct number of items even when 'nil' is present. See PIL chapter 6.2, Variadic Functions for a complete explanation.
Don't just hack something together, write your own datastructure for this. If you "overload" ipairs (by writing an appropriate iterator) you can use it as a table:
function create(...)
local t = table.pack(...)
local self = {
num = t.n,
elements = { ... }
}
return self
end
function elements(t)
local f = function(s, i)
i = i + 1
if i <= s.num then
return i, s.elements[i]
end
end
return f, t, 0
end
local seq = create(1, 2, nil, 3)
print(seq.num)
for i, e in elements(seq) do
print(i, e)
end
-- results:
-- 4
-- 1 1
-- 2 2
-- 3 nil
-- 4 3
You could know define a metatable for this structure and have it use its own ipairs, so you don't even have to change the name.
Well, you can't store nil in the table without issues.
The most simple solution here would be to introduce your own unique value.
local mynil = {} -- every new table is unique!
a = {1,2,3,mynil,4}
for k,v in ipairs(a) do
if (v == mynil) then
v = nil
end
print(k,v)
end
No more issues with "nil" string that might be stored in the table as well, the minor issue is one more comparison. ipairs or any other iterator will show that the key with mynil value exists. That means you can separate mynil key existence with missing key =nil.
P.S. If you want to shift your list, you may consider table.remove(list, key) function.
The answer to this is rather simple, and these "workaround a" suggested is definitely overkill. Just keep track of the number of items in your table whenever it's changed (note: do not use #, you have too keep track manually to deal with nil values) and use a numeric for loop to iterate over it.

Redis-Lua array key in string

I execute Lua under Redis. I face an issue which is that I can't use a string as an array key.
My coding is like following, and we found that mytable["wow"] is discarded:
FileName: hget.lua
local mytable = {}
mytable[1]= "Lua"
mytable["wow"] = "Tutorial"
return mytable
Command:redis-cli --eval hget.lua
Result returned is:
1) "Lua"
You CANNOT have a string key for the table, if you want to return the table to Redis.
Redis takes the returned table as an array, whose index starting from 1. It discards other elements of the table whose keys are NOT integers. In your case, i.e. mytable["wow"] = "Tutorial", since the key is a string, Redis ignores this element.
Also, the indexes must be sequential, otherwise, Redis discards some elements. Take the following as an example:
local t = {}
t[1] = "1" -- OK
t[2] = "2" -- OK
t[4] = "4" -- since index 3 is missing, this element will be discarded
t["string_key"] = "value" -- since the key is string, this element will be discarded
return t
Result:
./redis-cli --eval t.lua
1) "1"
2) "2"

LUA: Loop in 2d table to display first key name

Currently I'm stuck on this:
t = {['79402d'] = {'-5.4','5','1.6'}, ['5813g1'] = {'3','0.15','18'}}
Now i need to loop through this table to check if name == t[1], but how can i do so?
I tried doing something like: for i=1,#t,1 do print(t[i]) but it doesn't seem to work.
I hope you can help me guys ;)
Not sure why it didn't worked first time but i solved my problem with:
for a,b in pairs(t) do
print(a, b[1], b[2], b[3])
end
Please note that the length operator # will give you the correct number of elements in a table only in a special case. in your case #t will return 0, hence your for loop does nothing.
Please refer to https://www.lua.org/manual/5.3/manual.html Section 3.4.7 – The Length Operator for details on how to use the lenght operator.
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. so #t will be zero if you have no t[1] or n-1 if t[n] is the first nil value in your table starting from t[1].
As you have no t[1] but only a t['79402d'] and a t['5813g1'] your for loop indexing t[i] would not work anyway.
Please read 3.4.9 – Table Constructors on how table construction works.
t = {"hello", "world"}
is the same as
t = {}
t[1] = "hello"
t[2] = "world"
(here t[1] is "hello" and #t is 2
whereas t = {['key1'] = "hello", ['key2'] = "world"}
equals
t = {}
t['key1'] = "hello"
t['key2'] = "world"
so t[1] here is nil and #t is 0
# operator returns lenght of array part of the table. Your table is not an array (i.e. a table with non-nil values from index 1 to a given n). Because of that your loop is not iterating any elements.
Use pairs to iterate over all keys in the table regardless of what they are.

Lua: implicit table creation with string keys - why the extra brackets?

Say that you want to create a Lua table, and all its keys are valid lua identifiers. Then you can use the key=value syntax:
local niceTable = { I=1, like=1, this=1, syntax=1 }
If however your strings are not "identifiable", then you have to use the ['key']=value syntax:
local operators = { ['*']="Why", ['+']="the", ['/']="brackets", ['?']='?' }
I'm a bit baffled about this. What are those brackets doing there? What do they mean?
They identify the contained string as a key in the resulting table. The first form, you could consider as equal to
local niceTable = {}
niceTable.I = 1;
niceTable.like = 1;
The second form is equal to
local operators = {}
operators['*'] = "Why";
operators['+'] = "The";
The difference is purely syntactic sugar, except where the first one uses identifiers, so it has to follow the identifier rules, such as doesn't start with a number and interpret-time constant, and the second form uses any old string, so it can be determined at runtime, for example, and a string that's not a legal identifier. However, the result is fundamentally the same. The need for the brackets is easily explained.
local var = 5;
local table = {
var = 5;
};
-- table.var = 5;
Here, var is the identifier, not the variable.
local table = {
[var] = 5;
};
-- table[5] = 5;
Here, var is the variable, not the identifier.
The normal syntax for indexing a table is t[val]. For string keys only, Lua provides an alternate syntax, where t.foo is exactly equivalent to t["foo"]. This is purely a syntactical convenience, so-called 'syntax sugar'. It doesn't add functionality, it just gives you a less cluttered syntax for using strings as named fields.
There are a lot of strings keys this won't work for:
t["hello_world"] => t.hello_world -- works
t["hello world"] => t.hello world -- oops, space in the string
t["5 * 3"] => t.5 * 3 -- oops
t['[10]'] => t.[10] -- oops
Basically it only works if the string key would be a valid identifier.
Again, tables are indexed via [], and in most cases you need to use them:
t = {
-- [key] = value
[10] = "ten", -- number key, string value
["print function"] = print, -- string key, function value
["sub table"] = {}, -- string key, table value
[print] = 111, -- function key, number value
["foo"] = 123, -- string key, number value
}
Only if you're using a string key which would work as a valid identifier (no spaces, contains only word characters, numbers, or underlines, and doesn't begin with a number) can you use the shortcut syntax. For the table above, that would be only 'foo':
t = {
-- [key] = value
[10] = "ten", -- number key, string value
["print function"] = print, -- string key, function value
["sub table"] = {}, -- string key, table value
[print] = 111, -- function key, number value
foo = 123, -- string key, number value
}

Resources