Jump to content




Some lua tricks you may not have known...


106 replies to this topic

#21 hego555

  • Members
  • 89 posts

Posted 11 September 2012 - 06:34 AM

Are tables the equivalent of arrays?

#22 GopherAtl

  • Members
  • 888 posts

Posted 11 September 2012 - 07:09 AM

technically they are hashmaps, but they can act like arrays, like so...
--initialize a table like an array; lua will assign numeric keys starting with 1
local myArray={"cherries", "apples", "potatoes", "grapes", }

--use the # prefix operator to get the size of the array
print("myArray has "..#myArray.." items.")
--[[outputs :
myArray has 4 items
--]]

--you can use this to iterate over the array
function printArray(array)
  for i=1,#myArray do
	print(i..": "..myArray[i])
  end
end

printArray(myArray)
--[[outputs
1: cherries
2: apples
3: grapes
--]]

--they're still really hashmaps, so you can add arbitrary members too...
myArray.foo="bar"

--...but those non-numbered members are ignored when treating it like an array
print("myArray STILL has "..#myArray.." items.")
--outputs: "myArray STILL has 4 items")

--the table api, native to lua, provides some methods to help as well. You can remove items from the array..
table.remove(myArray,3)

printArray(myArray)
--[[ outputs
1: cherries
2: apples
3: grapes
--]]

--...or insert items

table.insert(myArray,2,"bananas")

printArray(myArray)
--[[ outputs
1: cherries
2: bananas
3: apples
4: grapes
--]]

--you can even sort them!
table.sort(myArray)
printArray(myArray)
--[[outputs:
1: apples
2: bananas
3: cherries
4: grapes
--]]

--though note, for this version of sort to work without errors, your array must contain all strings or all numbers.
table.insert(myArray,4,9001)
--calling table.sort(myArray) now would throw an error "attempt to compare string with number"

--however, mixed arrays, or even arrays of tables, can be sorted with a custom compare function!
function compareMixed(a,:D/>/>
  --convert both to strings first, then compare
  return tostring(a)<tostring(:)/>/>
end


--pass the function (WITHOUT ()s, just the name, like a variable!) to sort as 2nd parameter
table.sort(myArray,compareMixed)

printArray(myArray)
--[[ outputs:
1: 9001
2: apples
3: bananas
4: cherries
5: grapes
--]]

hope this helps :D/>

#23 ElectricOverride

  • Members
  • 94 posts

Posted 11 September 2012 - 03:50 PM

View PostKingdaro, on 20 August 2012 - 09:51 AM, said:

Lua Tricks
Note that this is not a lua tutorial and is intended for intermediate to advanced lua users.

I've been looking at some peoples' programs around here and I notice that a lot of them aren't using some neat tricks that may or may not make coding easier/neater.

Strings
The first thing is that a lot of people use double quotes instead of single quotes, but I think that's just a preference in most cases. In case you still aren't aware:
string1 = ''
string2 = ""

Both of these string variables are valid. I should probably mention that you should be careful with using single quotes, because there are common words with apostrophes such as "don't" and "you're". To prevent errors, you should put backslashes before single quotes inside single quotes:
string1 = 'don't'

An alternate solution is to use double quotes in this case.

There's also this neat trick that I didn't learn until a little further down the line in my use of lua - multiline strings. Defined by [[ ]], much like ' ' and " ".

The following example is valid:
print [[This is
a multiline
string.]]

Be wary that using multiline strings with tabs before text will actually output the tabs as well.
print [[This string
	  will take the tabbing
	  with it.]]

Multiline strings are useful in printing menus for your console. Instead of doing this:
print '------------------------------'
print 'Screen Title'
print '------------------------------'
print 'Option'
print 'Option'
print 'Option'

you can do:
print [[
------------------------------
Screen Title
------------------------------
Option
Option
Option
]]

A similar helpful trick to multiline strings can be done with comments, starting with --[[ and ending with ]]:
--[[
This is a multiline comment.
It does nothing :P/>/>
]]

I learned this very recently from an amazing youtuber named NitroFingers. You can use the # operator on strings to get the length of a string, much like string.len().
myString = 'waffles'

print(string.len(myString))
--> 7
print(#myString)
--> 7

I haven't tested this with all string methods, but in most cases, you'll usually be able to perform the method on the actual string instead of calling the method with the string as an argument.
local s = 'waffles'
s:sub(1,3)
--> waf
s:match 'f.-s'
--> fles

for i,v in s:gmatch '.' do
  print(v)
end
--> w
--> a
--> f
--> f
--> l
--> e
--> s

Functions
Function calls are also flexible in other ways. In the case that a function only takes one argument and it is a string, you don't have to supply parentheses.
print('a string')
print 'a string'
Both of these examples will print a string.

Unless you're getting deep into some OOP stuff, this won't be very helpful to you in a lot of cases. If a function takes a table argument, you can drop the parentheses, like strings.
myFunction {
a = 1;
b = 2;
}

There's also an alternate way of defining functions.
myFunct = function()
-- stuff
end

For me, this is useful for defining functions without having to go outside your table:
myTable = {
funct1 = function()
  print 'stuff'
end;

funct2 = function()
  print 'more stuff'
end;
}

myTable.funct1()
myTable.funct2()

Functions are able to be defined with a variable number of arguments:
function stuff(...)

end

The three dots represent the table of arguments given and can me accessed in the function as "arg".
function stuff(...)
for i,v in pairs(arg) do
  write(v)
end
end

stuff(1,2,3,'a','b','c')
--> 123abc6

Woah wait, where'd that 6 come from? That's just the number of arguments given. It's indexed in the "arg" table as n.
print(arg.n)
--> 6

However you'll still get the number of arguments given if you use the pound sign operator, as it only counts values given as indexes.
print(#arg)
--> 6

At the end of the day, it's all a matter of preference. To make things less complicated, you can simply store your arguments in a local table, as shown by some computercraft base programs.
tArgs = { ... }

Tables
When defining indexes in tables, you can actually use semicolons instead of commas. For me, this is easier because I can rearrange elements of the table without having to redo my commas.
myTable = {
index1 = "foobar";
index2 = 1337;
}

In case you didn't know this either, you can also use strings to access indexes not defined by strings. This would be helpful for storing functions for possible user input in tables.
local answers = {
yes = 'You're cool!';
no = 'Fine, be that way.';
}

print 'Do you like pineapples?'
input = read() -- this is accepted as a string.
if answers[input] ~= nil then
print(answers[input])
else
print 'I don't understand you, sorry.'
end

Numbers
There isn't much to learn in this category, however I think you'll eventually find it useful that you're actually able to concatenate numbers like strings.
print(3 .. 3)
--> 33
There need to be spaces in between the dots and the numbers, otherwise lua will confuse your dots as decimals and throw an error.

Some of you coming from a different programming background may have already known this, but the function math.fmod() can be replaced with the operator %. If you don't know what this does, it returns the remainder of the division of two numbers. e.g. 7 % 3 would equal 1.

You could use this to tell if a number is even - if the remainder of the number and 2 is 0.
while true do
  textutils.slowPrint 'Type in a number.'
  write '> '
  local input = read()
  local num = tonumber(input)
  if num then --checking if the input was successfully converted into a number
	if num % 2 == 0 then
	  textutils.slowPrint 'Your number is even.'
	else
	  textutils.slowPrint 'Your number is odd.'
	end
  elseif input == 'exit' then --give the ability to leave the program.
	textutils.slowPrint 'Thank you for using my useless program! :D/>/>'
	sleep(1)
	break
  else
	textutils.slowPrint "That's not a valid number!"
  end

  sleep(1)
end

Booleans
In the bools field, there's actually a cute little statement that is way easier than if ... elseif ... end:
var = condition and set_if_true or set_if_false
Five unnecessary lines condensed into one. Here's an example:

var = 5 > 3 and 'yes!' or 'aw'
In this case, var would be 'yes!' because 5 > 3. If on some distant alien planet in a parallel universe 5 were less than three, var would be 'aw'.

If you wanted to have a bit of fun, you can make yourself a clamp function by nesting these.
local function clamp(low,n,high)
return n < low and low or (n > high and high or n)
end

There's also a simple way of reversing a boolean:
bool = not bool

In a more applicable example, you could make a sort of toggling light switch program with one line (assuming your output is in the back and hooked up to your lights)
rs.setOutput('back', not rs.getOutput('back'))

Oh, and remember that % example? This:
	if num % 2 == 0 then
	  textutils.slowPrint 'Your number is even.'
	else
	  textutils.slowPrint 'Your number is odd.'
	end

Could be this:
	textutils.slowPrint('Your number is ' .. (num % 2 == 0 and 'even.' or 'odd.'))
Brackets needed because it isn't just one string anymore XD



You could've lived your life without knowing any of this, really. However I thought it'd be helpful to some of you people, a couple of interesting tidbits to know. Pretty sure I'm missing some stuff but I'm not necessarily a book of infinite useless lua knowledge :)/>
Thanks for the tips. :)/>

#24 hego555

  • Members
  • 89 posts

Posted 11 September 2012 - 10:30 PM

Dont quote the original post... its just a waste of space!

#25 Kingdaro

    The Doctor

  • Members
  • 1,636 posts
  • Location'MURICA

Posted 11 September 2012 - 11:45 PM

I understand you're probably new here, but please, please don't ever quote entire first posts.

#26 sjele

  • Members
  • 334 posts
  • LocationSomewhere on the planet called earth

Posted 13 September 2012 - 03:12 PM

Or use spoilers as that takes it down to only 2 lines, not so much spam

#27 lfairy

  • New Members
  • 5 posts
  • LocationChristchurch, New Zealand

Posted 16 September 2012 - 05:42 AM

Kingdaro, how about including the difference between pairs and ipairs?

The pairs function lets you loop over all the things in a table. For example:

local meanings = {
    python = 'a British comedy show',
    lua = 'the moon',
    java = 'a type of coffee',
    haskell = 'a famous computer scientist',
    c = 'the third letter of the alphabet',
    }

for key, value in pairs(meanings) do
    print('The language ' .. key .. ' is named after ' .. value)
end

But if you're going over a sequence (i.e. where the keys are numbers), pairs won't guarantee you'll get the values in order. Also, as you've shown with your vararg example, it often ends up returning extra values such as the length of the sequence.

To solve that issue, Lua has an alternative function called ipairs:

local languages = { 'python', 'lua', 'java', 'haskell', 'c' }
for index, value in ipairs(languages) do
    print('At index ' .. index .. ' we have ' .. value)
end


#28 Kingdaro

    The Doctor

  • Members
  • 1,636 posts
  • Location'MURICA

Posted 17 September 2012 - 11:54 PM

It's a good suggestion, though the subject of this topic is more oriented towards syntax abuse than anything.

I might include it in the future.

#29 Cloudy

    Ex-Developer

  • Members
  • 2,543 posts

Posted 18 September 2012 - 06:53 AM

It is worth pointing out that ipairs is deprecated and removed as of 5.2 - it is quicker to do this:
for i = 1, #tableTest do
  print("k: ", i, " v: ", tableTest[i])
end


#30 Kingdaro

    The Doctor

  • Members
  • 1,636 posts
  • Location'MURICA

Posted 19 September 2012 - 03:22 AM

Both pairs and ipairs are in 5.2, and I find using both of them easier than a numeric for statement. That way you don't have to index the table on every iteration and you have the value readily available.
for i=1, #aTable do
  print(i, aTable[i]) --longer
end

for i,v in pairs(aTable) do
  print(i, v) --shorter
end

Even though in this example it's just one statement, coding would be faster and easier in the longrun using "v" instead of "aTable[i]".

#31 Kingdaro

    The Doctor

  • Members
  • 1,636 posts
  • Location'MURICA

Posted 24 October 2012 - 03:26 AM

Learned something pretty neat a while ago. Added it under "Functions" (before Tables).

#32 KaoS

    Diabolical Coder

  • Members
  • 1,510 posts
  • LocationThat dark shadow under your bed...

Posted 24 October 2012 - 06:39 AM

hey man, why not include metatables in that, they are the most amazing tool I have yet seen in CC, another thing is that you can do the same with tables

({1,2,3,4,5})[2]==2

this seems pretty useless but it can be used to get a specific parameter from a function. for example if you only want the message from rednet but not the id we typically use

local _,message=rednet.receive()

but we could also use

local message=({rednet.receive()})[2]


#33 faubiguy

  • Members
  • 213 posts

Posted 24 October 2012 - 08:02 AM

View PostKaoS, on 24 October 2012 - 06:39 AM, said:

hey man, why not include metatables in that, they are the most amazing tool I have yet seen in CC, another thing is that you can do the same with tables

({1,2,3,4,5})[2]==2

this seems pretty useless but it can be used to get a specific parameter from a function. for example if you only want the message from rednet but not the id we typically use

local _,message=rednet.receive()

but we could also use

local message=({rednet.receive()})[2]

I usually use select to do that
local message = select(2, rednet.receive())


#34 KaoS

    Diabolical Coder

  • Members
  • 1,510 posts
  • LocationThat dark shadow under your bed...

Posted 24 October 2012 - 08:37 AM

that gives the second returned item and all items after it rather than just 1 but it makes little/no difference really. to be honest I did not know that function existed, good call there. I guess my example is pretty useless ^_^/> anyways it is another thing to know about lua, always good to gather info

#35 Kingdaro

    The Doctor

  • Members
  • 1,636 posts
  • Location'MURICA

Posted 24 October 2012 - 10:48 AM

View PostKaoS, on 24 October 2012 - 06:39 AM, said:

hey man, why not include metatables in that, they are the most amazing tool I have yet seen in CC, another thing is that you can do the same with tables

({1,2,3,4,5})[2]==2

this seems pretty useless but it can be used to get a specific parameter from a function. for example if you only want the message from rednet but not the id we typically use

local _,message=rednet.receive()

but we could also use

local message=({rednet.receive()})[2]
I forgot completely about metatables, haha.

I could tell people about the option to throw your function calls into a table and get specific arguments out of them, too. I myself don't prefer to do this but some would definitely benefit from knowing it.

#36 KaoS

    Diabolical Coder

  • Members
  • 1,510 posts
  • LocationThat dark shadow under your bed...

Posted 24 October 2012 - 11:02 AM

awesome stuff, in case it helps here is a link to the most helpful tutorial I have ever seen on metatables

#37 bbqroast

  • Members
  • 124 posts

Posted 28 October 2012 - 02:03 AM

I think there is a good reason for using double quotes as opposed to single quotes. In other languages like Java double quotes signify a string and single quotes signify a char.
So
"Hello World!" Is fine in most languages but 'Hello World!' can cause issues in some.

#38 Kingdaro

    The Doctor

  • Members
  • 1,636 posts
  • Location'MURICA

Posted 28 October 2012 - 06:30 AM

View Postbbqroast, on 28 October 2012 - 02:03 AM, said:

I think there is a good reason for using double quotes as opposed to single quotes. In other languages like Java double quotes signify a string and single quotes signify a char.
So
"Hello World!" Is fine in most languages but 'Hello World!' can cause issues in some.
But that's Java, it isn't Lua.

The only difference between double and single quotes is that double quotes can have single quotes inside, and vice versa.
 "It's useful if you want to have a statement with an apostrophe,"
'or if you want to "emphasize" something within single quotes.'


#39 bbqroast

  • Members
  • 124 posts

Posted 30 October 2012 - 08:59 PM

View PostKingdaro, on 28 October 2012 - 06:30 AM, said:

View Postbbqroast, on 28 October 2012 - 02:03 AM, said:

I think there is a good reason for using double quotes as opposed to single quotes. In other languages like Java double quotes signify a string and single quotes signify a char.
So
"Hello World!" Is fine in most languages but 'Hello World!' can cause issues in some.
But that's Java, it isn't Lua.

The only difference between double and single quotes is that double quotes can have single quotes inside, and vice versa.
 "It's useful if you want to have a statement with an apostrophe,"
'or if you want to "emphasize" something within single quotes.'
I believe some other languages do it as well. For that reason, it's still good practice to do it. It just makes it that much easier to change language, or try something new.

Also if you're doing a tutorial you need to remember that the reader may wish to move onto languages (LUA is a nice starting language) and it's bad to teach them thigns that will come back to bite them later.

#40 ChunLing

  • Members
  • 2,027 posts

Posted 31 October 2012 - 08:35 AM

Either is fine. I use double quotes unless I have a specific reason not to use them, in which case I'll usually go straight to the double brackets rather than muck about with single quotes. But as long as you're consistent about how you use them, string delineation is string delineation. It makes it a little easier to read your code if you write it the way you're used to reading it. Otherwise...not a big deal.





1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users