Redis-Lua array key in string - lua

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"

Related

How do I get information from a table in lua?

I have some lua code like this:
_table = {
stuff = {
item1 = {Name="Stack",Rarity="Over"};
item2 = {Name="Flow",Rarity="Com"}
};
};
print("placeholder") -- example thing
_stuff = _table.stuff
for i = 1, #_stuff do
print(_stuff[i].Name)
end
The output is this:
placeholder
I've tried to look at stuff but I don't think it was related to my problem.
Lua tables conceptually are "maps": They map keys to values. Your table _table maps the key stuff to the {item1 = ..., item2 = ...} table. Your stuff table maps the string "item1" to the {Name="Stack",Rarity="Over"} table and the string "item2" to the {Name="Flow",Rarity="Com"} table.
The length operator # completely ignores string keys. It returns an integer i such that t[i] ~= nil and t[i+1] == nil. In particular, it returns 0 if there are no integer keys in the table. This is the case for your stuff table: You only have string keys. Thus your loop never runs, as the limit is 0 and i = 1 > 0 already is the case before the first loop iteration.
Put simply, you're trying to iterate over a "dictionary" (a table with string keys) as if it were a list. Lua tables have both a "list part" (integer keys from 1 to n, where usually n = #t) and a "hash part" (of all other keys). The "list part" is empty in your case, so there's nothing for you to iterate over.
To iterate over all key-value pairs of any table (list or dictionary) in an undefined order, use pairs (rather than ipairs or iterating over indices i, which only works for lists):
for itemname, item in pairs(_stuff) do
print(item.Name)
end
If you want a defined order of iteration, either build a second table of keys...
local order = {"item1", "item2"}
for _, key in ipairs(order) do
print(_stuff[key].Name)
end
... or use the integer keys ("list part") of the table:
_table = {
stuff = {
{key = "item1", Name="Stack", Rarity="Over"};
{key = "item2", Name="Flow", Rarity="Com"};
};
};
_stuff = _table.stuff
for _, key in ipairs(order) do
for i = 1, #_stuff do
print(_stuff[i].Name)
end
end
then works as expected.

Get index of table Lua from string input

Suppose I have the following:
table = {a = {1, 2}, b = {3, 4}}
input = "a" -- abstracted away; it's a RV from another function.
You can use table.a[1] to get 1; however, I want to get it from the input variable - which is the return value of another function that I have, which returns the string "a" and not just a.
Now, this is where the error from here comes into play:
When I did table[input], it returned a table object, so then when I tried table[input][1], it had the calling a table error.
Is it possible to get 1 using indexing with the input "a"? If so, could someone let me know how this works? Thanks!
for any table if you use . to index it, it will use a string index.
When you use [] to index it, this means you can use any sort of datatype and it allows you to also use variables.
local someTable = {
a = "hello",
b = "world"
c = "!"
}
-- I can do
print(someTable.a) -- prints "hello"
-- and
print(someTable["b"]) -- prints "world"
-- however
print(someTable[c]) -- will error since there is no c variable
------
-- note that this would be valid
local someVariable = "c"
print(someTable[someVariable]) -- prints "!"
Going back to your case. tbl1 is using [] and using the variable input. However tbl2 is using the string "input" as the index in your table. Your table does not contain "input" as a key, so it returns nil
I hope I understand your question correctly, I apologize if not. If you want to, for example, send a specific part of a table to a user after they specified which key of the table they want then you're already doing everything correctly.
The tbl1 table contains the key "a" part of the main table. You can't print a table, but you can either print specific values by using tbl1[number] or do this:
table = {a = {1, 2}, b = {3, 4}}
input = "b"
tbl1 = table[input]
for _, v in pairs(table) do
print(v)
end
-- Expected output:
-- 3
-- 4

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

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

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
}

How to quickly initialise an associative table in Lua?

In Lua, you can create a table the following way :
local t = { 1, 2, 3, 4, 5 }
However, I want to create an associative table, I have to do it the following way :
local t = {}
t['foo'] = 1
t['bar'] = 2
The following gives an error :
local t = { 'foo' = 1, 'bar' = 2 }
Is there a way to do it similarly to my first code snippet ?
The correct way to write this is either
local t = { foo = 1, bar = 2}
Or, if the keys in your table are not legal identifiers:
local t = { ["one key"] = 1, ["another key"] = 2}
i belive it works a bit better and understandable if you look at it like this
local tablename = {["key"]="value",
["key1"]="value",
...}
finding a result with : tablename.key=value
Tables as dictionaries
Tables can also be used to store information which is not indexed
numerically, or sequentially, as with arrays. These storage types are
sometimes called dictionaries, associative arrays, hashes, or mapping
types. We'll use the term dictionary where an element pair has a key
and a value. The key is used to set and retrieve a value associated
with it. Note that just like arrays we can use the table[key] = value
format to insert elements into the table. A key need not be a number,
it can be a string, or for that matter, nearly any other Lua object
(except for nil or 0/0). Let's construct a table with some key-value
pairs in it:
> t = { apple="green", orange="orange", banana="yellow" }
> for k,v in pairs(t) do print(k,v) end
apple green
orange orange
banana yellow
from : http://lua-users.org/wiki/TablesTutorial
To initialize associative array which has string keys matched by string values, you should use
local petFamilies = {["Bat"]="Cunning",["Bear"]="Tenacity"};
but not
local petFamilies = {["Bat"]=["Cunning"],["Bear"]=["Tenacity"]};

Resources