22
4
What general tips do you have for golfing in Lua? I'm looking for ideas that can be applied to code golf problems in general that are at least somewhat specific to Lua (e.g. "remove comments" is not an answer). Please post one tip per answer.
22
4
What general tips do you have for golfing in Lua? I'm looking for ideas that can be applied to code golf problems in general that are at least somewhat specific to Lua (e.g. "remove comments" is not an answer). Please post one tip per answer.
9
In addition to the ones already posted, here are some tricks I've gathered over time, in no specific order...
For the function calls that only have one parameter delimited by a symbol ("
for strings, {
for tables), the parameter doesn't need to be wrapped around parentheses.
For example, instead of doing print("hello")
, you can simply do : print"hello"
Remove as much whitespace as possible - this is especially easy to do after a symbol that closes strings (or before one opening), function calls, tables...
Instead of print(42) a=1
you can do print(42)a=1
. Other example: print(a and-1 or-2)
.
Use the ternary operator when you can! Instead of if a>0 then print("hello") else print("goodbye") end
, prefer print(a>0 and "hello" or "goodbye")
. More info here.
(This can actually get even better : print(a>0 and"hello"or"goodbye")
)
Use the colon-call syntactic sugar when you can : instead of string.rep(str,12)
, do str:rep(12)
. That also works on non-variables this way (and only this way) : ("a"):rep(5)
Instead of doing tonumber(str)
just do str+0
For functions with no parameters, instead of defining them the usual way (function tick() blabla() end
), you can do : ticks=loadstring"blabla()"
, which saves 1 or more bytes, depending on the content. Also, if you define multiple functions, localize loadstring
to a 1-char variable before and you'll save a lot of bytes ;). Credits to Jim Bauwens for this trick.
Lua considers empty string (and 0
too unlike other languages) as true in conditional tests, so, for example, instead of doing while 1 do ... end
, save 1 byte by writing while''do ... end
20 being a truthy value is just silly – SuperJedi224 – 2016-02-02T14:21:07.597
another str+0
equivalent is ~~str
, can be usefull for it's precedence – Felipe Nardi Batista – 2017-06-15T14:05:15.973
@FelipeNardiBatista however that's only supported on Lua 5.3+ – Adriweb – 2017-06-15T14:52:02.580
(Added the loadstring trick) – Adriweb – 2014-08-24T10:00:00.533
5
I have already thought of one.
I don't know if it works in some other languages, but Lua is the only one I know what allows you to store functions in variables. So if e.g. string.sub
is used multiple times in your program, use e.g. s=string.sub
.
This is equivalent to s=("").sub
or s=a.sub
for any variable a
containing string value. – Egor Skriptunoff – 2015-10-12T19:36:22.113
This is called first class functions – Redwolf Programs – 2019-10-28T12:28:48.700
4It also works in many other languages such as Python and Ruby. – nyuszika7h – 2014-04-21T19:16:36.883
4Javascript and Haskell can have function values too. – proud haskeller – 2014-09-17T23:04:57.303
5
It's a pretty verbose language for golfing... but some general tips that come to mind are:
if
...then
...else
...end
is a major waste.for i=1,5 do
.#
operator is pretty great for golfing (and in general).5
Shorten your infinite loop
When you have to use an infinite loop, you may think of using a while
, but using a label instead is shorter by 2 byte:
while''do end
::a::goto a
Use the less space as possible
There's a simple thing you could (ab)use to remove even more spaces from your code. Lua's specs are clear about the name you give to variables: They have to start with a letter. It imply that, sometimes, you can skip on spaces between numbers and functions/variables
x=0>1 and 0or 1print(x)
The possibility of removing the space depends on the letter following the number, here's the letter that won't allow you to do this:
a,b,c,d,e,f -- They would be interpreted as hexadecimal
x -- only fail when after a 0, other number are fine
-- (0x indicates the following is an hexadecimal number)
By using this, and paying attention to how you call your variables, you can make most of your source codes space-free.
Picking up an example already here, and using this advice, here's one more byte you could shaved off :).
print(a and-1 or-2)
print(a and-1or-2)
Use the right input method
If we look at the boilerplate and cost for each major type of input, here's what we have:
function f(x)x end
io.read()
arg[1]
Each one of this method allow us to take 1 input, with the function being the one with the heaviest cost (but allows us to take a table as input)
We can now see that using command-line argument is the way-to-go if you want to golf, but be aware: it can be even shorter
arg[1]
...
The ...
are a bit special in lua, it's a variable containing the unpacked content of arg
, or the unpacked parameters in case of a variadic function.
When you will have to get more than one input, and use each of them, it can be good to do save them in a variable. Here's some ways to save 2 inputs in variables
a=arg[1]b=arg[2] -- highly un-efficient, costs 8 bytes by variable
a,b=unpack(arg) -- costs 15, but at least doesn't depends on the number of argument
a,b=... -- only costs 7
and here are the shortest call you could have done without the variables:
... -- using a allow a gain of 1-2 bytes at each use
arg[2] -- using b allow a gain of 4-5 bytes at each use
From the point where you have 3 argument, or when you use 2 arguments, with one used twice, you're already gaining bytes due to a,b=...
! :)
Almost never use if!
There's near no cases where using a if/elseif/if statement will cost less than a ternary. the boilerplate for such a statement is really heavy:
-- exemple with dumb values
if 1>0then v=1 else v=0 end
v=1>0 and 1or 0
With a simple example, you already save 12 bytes, when you have to do some elseifs, it become more and more important, so be aware of that!
Also, ternaries in lua are special, there's some condition in how they work, for those interested, I'll explain it below:
Ternaries in lua are of the form <condition> and <case true: have to be a true value> or <case false: can be anything>
First of all, let's see the truth table of the or
. A or
can be considered as a function: it always return a value, here's the value it returns:
x | y ||x or y
------||-------
0 | 0 || y
0 | 1 || y
1 | 0 || x
1 | 1 || x
That's what allow us to construct our ternary.
The and
is what allow us to evaluate the condition, it will always return y
if x and y
evaluates to true.
The problem with it is that it will fail if we want a nil
or false
to be return when the condition is false
. For instance, the following will always return 5, despite the condition being true.
v = true and false or 5
Here's a step by step evaluation of a ternary to explain how it works (it will be useful for when you have to nest them :))
-- let's use our dumb ternary
= true and false or 5
-- and statement will be evaluated first, leading to
= false or 5
-- and we saw how the or works
= 5
One tip per answer, please. – ATaco – 2016-11-07T02:26:47.373
Note that the "Use the less space as possible" trick only works on Lua 5.2 and later. – Adriweb – 2019-05-14T05:05:38.357
4
I have compiled several tips as well. I'm sure some of mine will overlap with ones already stated, but I'll include them anyhow in the vein of creating a more complete answer.
Assign repeated functions to variables
Lua allows you to assign functions to variables. Even one character variables. This means if you repeat the function string.sub(x, y)
more than twice, you will get a benefit from assigning it to a variable.
Without assigning to a variable (69 characters):
print(string.sub(x, y))
print(string.sub(x, y))
print(string.sub(x, y))
Assigning to a variable (51 characters):
s=string.sub
print(s(x,y))
print(s(x,y))
print(s(x,y))
There's cases where you can take this yet a step further. Lua allows an OOP to string manipulation, like so: str:sub(x, y)
or str.sub(x, y)
This opens up new options for our code.
You can assign a variable to the function by it's reference as shown (46 characters.)
s=z.sub
print(s(x, y))
print(s(x, y))
print(s(x, y))
Use the most efficient way to parse strings
You may find yourself using a for
loop and string.sub
to iterate character by character in Lua. Sometimes this may work best, depending on your needs, but other times, string.gmatch will work in fewer characters. Here's an example of both:
s=io.read()
for a = 1, s:len() do
print(s:sub(a, a))
end
for i in io.read():gmatch('.') do
print(i)
end
And when golfed, the difference is more notable:
s=io.read()for a=1,s:len()do print(s:sub(a, a))end
for i in io.read():gmatch'.'do print(i)end
Restructure Assignations To Optimize Whitespace
In Lua, you do not have to put a space character between a closed parentheses or a end quotation mark and the next character. So far, I've found two cases where restructuring with this in mind will cut characters.
Assigning variables:
x,y=io.read(),0 print(x)
vs.
y,x=0,io.read()print(x)
If Statements:
if x:sub(1,1)==1 then
vs
if 1==x:sub(1,1)then
Return the fewest characters possible
If you must return a true or false value, then it seems you must necessarily use at least 5 characters for the return value. In reality the following works just as well:
return true
return false
vs
return 1>0
return 0>1
Great tips, I've taken the liberty to suggest an edit to your post. Only nil
and false
evaluates to false in lua, everything else is true, so your tips about replacing x==0
,x==""
and x==''
by x
is false. I'm currently changing it to nil
:). – Katenkyo – 2016-02-02T09:31:08.430
Ah, you are correct. Thank you for fixing that! – Skyl3r – 2016-02-02T13:20:31.210
2
These are Lua only (I think) optimizations:
Strings are automatically converted into numbers when doing arithmetic operations on them. Just watch out for conditional statements, they do not automatically convert. This is great for taking user input as numbers while saving space.
Switching the contents of two variables does not require a temporary variable. a,b=b,a
will swap the values of a and b.
Also, to extend upon what was said above, any alphanumeric character can touch a non alphanumeric character. So a,b=io.read():match"(.+)/(.+)"u,v=a,b
is a perfect, working script, even with the lack of whitespace.
2
Instead of:
local a=42
local b=17
local c=99
Use parallel assignment:
local a,b,c=42,17,19
6 bytes saved for each variable!
Instead of:
function foo(a,b) local c,d ... end
function bar(a,b) local c,d=42,17 ... end
Use
function foo(a,b,c,d) ... end
function bar(a,b,c,d) c,d=42,17 ... end
6 bytes saved (minus 1-2 bytes for each variable that might be duplicated).
1Downvoted because there's absolutely no case where using local
is justified when golfing, because you just have to use a different name. We could use ALL the names up to 7 charachters AND tables with string indexes up to 7 charachters combinations before we're hitting something that could benefit from using locals – Katenkyo – 2017-10-25T23:49:37.813
1
There's two main method of outputting in lua
io.write() -- outputs without trailing newline
print() -- outputs with trailing new line and shorter by 3 bytes
When you have to concatenate multiple times, you could shorten that by using io.write()
assigned to a one letter variable instead of the standard concatenation operator ..
i(a) -- i was defined as io.write
s=s..a
You gain 2 bytes at each call while paying some upfront
i=io.write -- longer by 6 bytes
s=""
You're even on the third concatenation, and start gaining byte on the fourth.
3It is print
and not printf
! – val says Reinstate Monica – 2019-10-28T11:41:49.183
@val Wow, I don't even know how I could do that mistake. Thanks for pointing it out, I'll edit – Katenkyo – 2019-10-29T10:54:36.297
1
The main variadic function that will trouble you is print()
. For instance, when you're using it along String.gsub()
it will print the string you modified AND the number of times gsub
triggered.
To supress that second output, encapsulate your gsub
in parens to force it to return only one value
print(String.gsub("aa",".","!")) -- outputs "!! 2\n"
print((String.gsub("aa",".","!"))) -- outputs "!!\n"
1
A bunch of tips in no particular order:
string
is pretty long name. Efficiently, ('').char
is same as string.char
. Even better results can be achieved if you use it together with a semicolon on variables: a=...; print(a:sub(1, 5))
, but some string
functions don't take strings as input.tonumber
and +0
often only waste bytes.load'your function code here'
instead of function()your function code here end
. Access function arguments using ...
inside.a:gsub('.',load'my function')
seems to be the shortest way to iterate over chars in a stringa:find('.',1,1)
(to test for this issue, try including %
at various places in your input and check out results). Countless ideas broke because of Lua trying to parse input as pattern.nil
is three bytes, _
is one (it is just random name which most likely doesn't exist). Also, any digit will work as truthy value.x and i or o
. It isn't just a ternary operator - it is a complete logical expression. In fact, it means the following: "if x
is truthy, try i
. If either x or i is falsy, return o". So if i
is not truthy, result is o
. Also, both and
or or
parts can be omitted (x and i
, x or o
).math.floor
: 5.3//1==5.0
. Please note that the resulting number always follows the type of input one (integer/float).1"Also, any digit will work as truthy value." Just wanted to elaborate that this includes 0, which might not be very intuitive to some coders from a C/C++ background. – ouflak – 2019-10-30T08:10:19.070
6Tips questions should be community wiki. But to whoever submitted this for close as "primarily opinion-based", the Tips for Golfing in Language questions are our accepted exception to that rule. The open-ended nature of these questions is why they are community wiki-ed. – Jonathan Van Matre – 2014-03-17T16:18:47.663