I understand what colon syntax does. I know what table.insert(list, value) does. I'm also aware that I cannot create my own table t={} and insert a value to it with t:insert(value). But when I do table:insert(value) it inserts the value to table which is supposed to a type, right? The worst thing is that I can read this value by calling table[1]. What did I just do? How did I insert a value into a type? Why regular tables don't support colon syntax? I tried to Google it up but I just get information about tables in general, not about this particular case.
What did I just do?
The syntax A:B(C) is nearly equivalent to A.B(A, C), you can check my another answer: link.
So table:insert(value) just means table.insert(table, value), it inserts value into the table table (have nothing to do with t).
How did I insert a value into a type?
table.insert(t, value)
Why regular tables don't support colon syntax?
Because t:insert(value) means t.insert(t, value), but this regular table doesn't have the key insert.
You can solve this by adding the function to the table
t.insert = table.insert
Or using a metatable
setmetatable(t, {__index = {insert = table.insert}})
In Lua the only datatypes where you can use the colon directly for assigned datatype specific methods are string and userdata
But its easy to set the table functions as methods on self created tables...
> myTable = setmetatable({}, {__index = table})
Than you can do...
> myTable:insert("Hi")
> myTable:insert("There")
> print(myTable:concat(" "))
Hi There
But chaining the table methods like the most string methods is not possible.
Because for chaining the method has to return what the next method can work with (as argument).
Like...
> print(("Hi there"):upper():rep(10, ", ")) -- Chaining methods on datatype string
HI THERE, HI THERE, HI THERE, HI THERE, HI THERE, HI THERE, HI THERE, HI THERE, HI THERE, HI THERE
But you can chain what myTable:concat() will return with string methods...
> print(myTable:concat(" "):rep(10, ", "):upper())
HI THERE, HI THERE, HI THERE, HI THERE, HI THERE, HI THERE, HI THERE, HI THERE, HI THERE, HI THERE
Because myTable:concat() returns a string.
PS: Thinking about datatype specific methods and deciding to add math functions for datatype number as methods
That will be done with...
> debug.setmetatable(1, {__index = math})
Than math and calculating with datatype number becomes some magic...
> print((0.0).pi) -- Any number has pi
3.1415926535898
> print((1.1).pi:deg()) -- Convert pi to degrees
180.0
> print((180):rad()) -- Convert 180 degrees to radians
3.1415926535898
> print(("%a"):format((1).pi)) -- Pi to HEX float (string)
0x1.921fb54442d18p+1
> print((0x1.921fb54442d18p+1):deg()) -- HEX float to degrees
180.0
Related
I see several posts about making a string in to a lua table, but my problem is a little different [I think] because there is an additional dimension to the table.
I have a table of tables saved as a file [i have no issue reading the file to a string].
let's say we start from this point:
local tot = "{{1,2,3}, {4,5,6}}"
When I try the answers from other users I end up with:
local OneDtable = {"{1,2,3}, {4,5,6}"}
This is not what i want.
how can i properly create a table, that contains those tables as entries?
Desired result:
TwoDtable = {{1,2,3}, {4,5,6}}
Thanks in advance
You can use the load function to read the content of your string as Lua code.
local myArray = "{{1,2,3}, {4,5,6}}"
local convert = "myTable = " .. myArray
local convertFunction = load(convert)
convertFunction()
print(myTable[1][1])
Now, myTable has the values in a 2-dimensional array.
For a quick solution I suggest going with the load hack, but be aware that this only works if your code happens to be formatted as a Lua table already. Otherwise, you'd have to parse the string yourself.
For example, you could try using lpeg to build a recursive parser. I built something very similar a while ago:
local lpeg = require 'lpeg'
local name = lpeg.R('az')^1 / '\0'
local space = lpeg.S('\t ')^1
local function compile_tuple(...)
return string.char(select('#', ...)) .. table.concat{...}
end
local expression = lpeg.P {
'e';
e = name + lpeg.V 't';
t = '(' * ((lpeg.V 'e' * ',' * space)^0 * lpeg.V 'e') / compile_tuple * ')';
}
local compiled = expression:match '(foo, (a, b), bar)'
print(compiled:byte(1, -1))
Its purpose is to parse things in quotes like the example string (foo, (a, b), bar) and turn it into a binary string describing the structure; most of that happens in the compile_tuple function though, so it should be easy to modify it to do what you want.
What you'd have to adapt:
change name for number (and change the pattern accordingly to lpeg.R('09')^1, without the / '\0')
change the compile_tuple function to a build_table function (local function build_tanle(...) return {...} end should do the trick)
Try it out and see if something else needs to be changed; I might have missed something.
You can read the lpeg manual here if you're curious about how this stuff works.
I am really newbie in lua. I have this lua code
local gun_info = {
g_sword={rate=0.5;spd=0;dmg=1;ammo=1;};
g_pistol={rate=0.5;spd=5;dmg=1;ammo=40;};
g_knife={rate=0.8;spd=5;dmg=1;ammo=1;};
g_shuriken={rate=0.3;spd=5;dmg=1;ammo=40;};
g_bomb={rate=0.8;spd=5;dmg=1;ammo=20;};
};
I just want get values of every ammo. Other properties are no needed.
for k, v in pairs(gun_info) do
print(k, v[1], v[2], v[3], v[4], v[5])
end
this prints out whole tables but I need just value of ammos
Use comma between table variables rather than semicolon. Using semicolon is not syntactically wrong but optional in Lua. Semicolon is usually used to separate multiple statements written in single line.
You can directly access the variable ammo by indexing the key of the table
for k, v in pairs(gun_info) do
print(k, v.ammo)
end
v.ammo and v[ammo] are not same in Lua.
Note: The order in which the elements appear in traversal will not be the same as you defined and can produce different order each time. This is due to the way tables are implemented in Lua.
I want to know how to get the table hex id. I know that doing:
local some_var = {}
print (some_var)
the result is (for instance):
table: 0x21581c0
I want the hex without the table: string. I know that maybe some of you suggest me to make a regular expression (or something similar) to remove those chars, but I want to avoid that, and just get the 0x21581c0
Thanks
This is simpler and works for all types that are associated with pointers:
local function getId(t)
return string.format("%p", t)
end
print("string:", getId("hi"))
print("table:", getId({}))
print("userdata:", getId(io.stdin))
print("function:", getId(print))
print("number:", getId(1))
print("boolean:", getId(false))
print("nil:", getId(nil))
Result:
string: 0x0109f04638
table: 0x0109f0a270
userdata: 0x01098076c8
function: 0x0109806018
number: NULL
boolean: NULL
nil: NULL
In the standard implementation, there is the global 'print' variable that refers to a standard function that calls, through the global variable 'tostring', a standard function described here. The stanard 'tostring' function is the only way to retrieve the hexadecimal number it shows for a table.
Unfortunately, there is no configuration for either of the functions to do anything differently for all tables.
Nonetheless, there are several points for modification. You can create you own function and call that every time instead, or point either of the the global variables print or tostring to you own functions. Or, set a __tostring metamethod on each table you need tostring to return a different answer for. The advantage to this is it gets you the format you want with only one setup step. The disadvantage is that you have to set up each table.
local function simplifyTableToString(t)
local answer = tostring(t):gsub("table: ", "", 1)
local mt = getmetatable(t)
if not mt then
mt = {}
setmetatable(t, mt)
end
mt.__tostring = function() return answer end
end
local a = {}
local b = {}
print(a, b)
simplifyTableToString(a)
print(a, b)
Without complex patterns, you can just search for the first space, and grab the substring of what follows.
function get_mem_addr (object)
local str = tostring(object)
return str:sub(str:find(' ') + 1)
end
print(get_mem_addr({})) -- 0x109638
print(get_mem_addr(function () end)) -- 0x108cf8
This function will work with tables and functions, but expect errors if you pass it anything else.
Or you can use a little type checking:
function get_mem_addr (o)
return tostring(o):sub(type(o):len() + 3)
end
The table id stated by the OP is invalid in the version of Lua I am using (5.1 in Roblox). A valid ID is length 8, not 9 as in your example. Either way, just use string.sub to get the sub-string you are after.
string.sub(tostring({}), 8)
The reason is, 'table: ' is 7 characters long, so we take from index 8 through the end of the string which returns the hex value.
Easy question here, probably, but searching did not find a similar question.
The # operator finds the length of a string, among other things, great. But with Lua being dynamically typed, thus no conversion operators, how does one type a number as a string in order to determine its length?
For example suppose I want to print the factorials from 1 to 9 in a formatted table.
i,F = 1,1
while i<10 do
print(i.."! == "..string.rep("0",10-#F)..F)
i=i+1
F=F*i
end
error: attempt to get length of global 'F' (a number value)
why not use tostring(F) to convert F to a string?
Alternatively,
length = math.floor(math.log10(number)+1)
Careful though, this will only work where n > 0!
There are probably a dozen ways to do this. The easy way is to use tostring as Dan mentions. You could also concatenate an empty string, e.g. F_str=""..F to get F_str as a string representation. But since you are trying to output a formatted string, use the string.format method to do all the hard work for you:
i,F = 1,1
while i<10 do
print(string.format("%01d! == %010d", i, F))
i=i+1
F=F*i
end
Isn't while tostring(F).len < 10 do useful?
In Lua, there seem to be two ways of appending an element to an array:
table.insert(t, i)
and
t[#t+1] = i
Which should I use, and why?
Which to use is a matter of preference and circumstance: as the # length operator was introduced in version 5.1, t[#t+1] = i will not work in Lua 5.0, whereas table.insert has been present since 5.0 and will work in both. On the other hand, t[#t+1] = i uses exclusively language-level operators, wheras table.insert involves a function (which has a slight amount of overhead to look up and call and depends on the table module in the environment).
In the second edition of Programming in Lua (an update of the Lua 5.0-oriented first edition), Roberto Ierusalimschy (the designer of Lua) states that he prefers t[#t+1] = i, as it's more visible.
Also, depending on your use case, the answer may be "neither". See the manual entry on the behavior of the length operator:
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).
As such, if you're dealing with an array with holes, using either one (table.insert uses the length operator) may "append" your value to a lower index in the array than you want. How you define the size of your array in this scenario is up to you, and, again, depends on preference and circumstance: you can use table.maxn (disappearing in 5.2 but trivial to write), you can keep an n field in the table and update it when necessary, you can wrap the table in a metatable, or you could use another solution that better fits your situation (in a loop, a local tsize in the scope immediately outside the loop will often suffice).
The following is slightly on the amusing side but possibly with a grain of aesthetics. Even though there are obvious reasons that mytable:operation() is not supplied like mystring:operation(), one can easily roll one's own variant, and get a third notation if desired.
Table = {}
Table.__index = table
function Table.new()
local t = {}
setmetatable(t, Table)
return t
end
mytable = Table.new()
mytable:insert('Hello')
mytable:insert('World')
for _, s in ipairs(mytable) do
print(s)
end
insert can insert arbitrarily (as its name states), it only defaults to #t + 1, where as t[#t + 1] = i will always append to the (end of the) table. see section 5.5 in the lua manual.
'#' operator only use indexed key table.
t = {1, 2 ,3 ,4, 5, x=1, y=2}
at above code
print(#t) --> print 5 not 7
'#' operator whenever not using.
If you want to '#' operator, then check it to table elements type.
Insert function can using any type use.But element count to work slow than '#'