How can I get only the decimal from a float in lua? - lua

How would I be able to do the following?
local d = getdecimal(4.2) --> .2

Assuming you're only working with numbers greater than 0, modulus is the best way to go:
print(4.2%1)
Otherwise the fmod function in the math library should do the trick.
print(math.fmod(4.2,1))

You can take a little bit of a non-paradigmatic approach to this by taking the number and turning it into a string:
function getDec(num)
return tostring(num):match("%.(%d+)")
end
print(getDec(-3.2))
--2

function getDecimal(inp)
local x = tostring(inp)
local found_decimal = false
local output_stream = ""
for i = 1, string.len(x) do
if found_decimal == false then
if string.sub(x, i+1, i+1) == "." then
found_decimal = true
end
else
output_stream = output_stream .. string.sub(x,i, i)
end
end
return output_stream
end
What that does is it basically returns everything after the decimal it found as a string.
And if you want to turn the return back into a number do this:
return tonumber("0" .. output_stream)

Related

Lua recursive function with variable arguments

I am trying to write a string join function that will work with both tables and variable arguments as input. Here is what I have so far:
function join(separator, ...)
local result = ""
local vargs = {...}
local n = #vargs
for i = 1, n do
local varg = vargs[i]
if type(varg) == "table" then
result = join(separator, result, table.unpack(varg))
elseif varg ~= nil then
result = result..tostring(varg)
if i < n then
result = result..separator
end
end
end
return result
end
However, when I try to use it with the following input:
print(join(",", "1", "2", "3"))
print(join(",", {"a", "b", "c"}))
The output is this:
1,2,3
,a,b,c
I did not expect the , at the beginning of a,b,c.
From what I understand, it seems somehow the separator is getting added to the variable arguments when calling the function inside the function (recursiveness). But why is that? And how can I fix it? Thank you!
Try
...
if type(varg) == "table" then
varg = join(separator, table.unpack(varg))
end
if varg ~= nil then
...
Well uh sorry if it's not really useful but maybe it's because you put the: , into "" that it print the ,

Why is this string not splitting in lua

So I am working on a project and I need to split a string that would look something like this:
if (x == 2){ output("Hello") }
This is my code:
local function splitIfStatement(str)
local t = {}
t[1] = ""
t[2] = ""
t[3] = ""
local firstSplit = false
local secondSplit = false
local thirdSplit = false
str:gsub(".", function(c)
if c == "(" then
firstSplit = true
end
if firstSplit == true then
if c == "=" then
firstSplit = false
secondSplit = true
else
if c == "(" then
else
t[1] = t[1] .. c
end
end
end
if secondSplit == true then
if c == ")" then
secondSplit = false
thirdSplit = true
else
if c == "=" then
else
t[2] = t[2] .. c
end
end
end
end)
return t
end
I need to split the string at "(" so t[1] is only equal to "x" and t[2] is equal to 2 and then t[3] is equal to the "output()"
But when I run my code(note I haven't added the t[3]) t[1] returns: "x "Hello") }" and t[2] returns 2 like it should.
Anyways why isn't the split function working on the first split but it works on the second.
Thanks!
In your loop you set firstSplit true if it hits a ( this happens in 2 places in your example, before x and right before "Hello"
you can fix this by setting firstSplit true and ignore the leading if ( before you beginning the loop. Then you allow the logic you have to handle the rest.
I also notice you dont have any logic that references t[3] right now.
That all said you really should use a pattern to parse something like this.
local function splitIfStatement(str)
t = {str:match("if%s*%((%w+)%s*[=<>]+%s*(%d+)%)%s*{(.+)}")}
return t
end
this pattern is very narrow and expects a specific type of if statement, you can learn more about lua patterns here: Understanding Lua Patterns
If the input is of the form
if (AAA == BBB){ CCC("Hello") }
with possible whitespace around the fields in question, then this code works:
S=[[if (x == 2){ output("Hello") } ]]
a,b,c = S:match('%(%s*(.-)%s.-%s+(.-)%)%s*{%s*(.-)%(')
print(a,b,c)

Boolean function arguments and returning

so i know you can do stuff like this in lua to kind of shorten your code so you don't have to make unnecessary if statements
function checkMath(equation)
if equation == 4 then
return true
end
return false
end
workspace.Part.BrickColor = BrickColor.Green() or BrickColor.Red()
but is there a way to do that for a return statement inside a function?
basically, what I'm asking is: is it possible to return amount and items if returnItems is true or only amount if returnItems is false without a if statement?
what I've thought of doing (haven't tested):
countDictItems = function(tab,returnItems)
local amount = 0
local items = {}
for _, ind in pairs(tab) do
amount = amount + 1
end
return amount, items or amount
end
Answered in a separate thread I posted on another website.
function blah(returnitems)
amount = 15
items = {"blah1", "blah2"}
return amount, returnitems and items or nil
end
print(blah(true))
print(blah(false))
output:
>15 table: 0x9e26e0
>15 nil

Count number of occurrences of a value in Lua table

Basically what I want to do is convert a table of this format
result={{id="abcd",dmg=1},{id="abcd",dmg=1},{id="abcd",dmg=1}}
to a table of this format:
result={{id="abcd",dmg=1, qty=3}}
so I need to know how many times does {id="abcd",dmg=1} occur in the table. Does anybody know a better way of doing this than just nested for loops?
result={{id="abcd",dmg=1},{id="defg",dmg=2},{id="abcd",dmg=1},{id="abcd",dmg=1}}
local t, old_result = {}, result
result = {}
for _, v in ipairs(old_result) do
local h = v.id..'\0'..v.dmg
v = t[h] or table.insert(result, v) or v
t[h], v.qty = v, (v.qty or 0) + 1
end
-- result: {{id="abcd",dmg=1,qty=3},{id="defg",dmg=2,qty=1}}
So you want to clear duplicate contents, although a better solution is to not let dupe contents in, here you go:
function Originals(parent)
local originals = {}
for i,object in ipairs(parent) do
for ii,orig in ipairs(originals) do
local dupe = true
for key, val in pairs(object) do
if val ~= orig[key] then
dupe = false
break
end
end
if not dupe then
originals[#originals+1] = object
end
end
return originals
end
I tried to make the code self explanatory, but the general idea is that it loops through and puts all the objects with new contents aside, and returns them after.
Warning: Code Untested

if statement not working in Lua for io.read

I'm trying to make a 'simple' Y/N answer choice thing. (That you saw all the time on old programs) But an If Statement I'm using doesn't seem to want to work. I even print out the variable and it is nowhere near what i want to compare yet it still passes it.
--Porgram Functions
function check()
--Local Variables
local num = 0
local loop = true
io.write("Continue? (Y/N):")
--User input
local input = io.read()
while(loop==true) do
if (input=="y" or "Y") then
print("Ok!")
loop = true
num = 1
elseif (input=="n" or "N") then
print("Fine...")
num = 2
else
print("Invalid Answser!")
loop = true
num = 0
end
end
print(input)
return(num)
end
print (check())
I would've written your function like this:
function check()
io.write("Continue? (Y/N): ")
answer = io.read()
while( not (answer == "Y" or answer == "N") ) do
io.write("Invalid Answer! Try again (Y/N): ")
answer = io.read()
end
if answer == "Y" then
print("Ok!")
return 1
else
print("Fine...")
return 2
end
end
print(check())
Some examples of its use:
Continue? (Y/N): Huh?
Invalid Answer! Try again (Y/N): N
Fine...
2
>Exit code: 0
>lua -e "io.stdout:setvbuf 'no'" "a.lua"
Continue? (Y/N): Huh?
Invalid Answer! Try again (Y/N): Y
Ok!
1
A working version of your code would be:
function check()
local num = 0
local loop = true
io.write("Continue? (Y/N):")
while(loop==true) do
--User input
local input = io.read()
if (input == "y" or input == "Y") then
print("Ok!")
num = 1
loop = false --we want to stop looping if input is valid
elseif (input == "n" or input == "N") then
print("Fine...")
num = 2
loop = false --we want to stop looping if input is valid
else
print("Invalid Answser!")
-- loop = true no need to set looping to true again
num = 0
end
end
return(num)
end
The changes made were:
Get the user input inside the while loop, this way if the input is invalid and the loop goes again the same logic behind getting the input is used, we don't have to code two cases for getting input; one outside the loop the other within. It also pauses execution when the loop starts again, this was what was producing all that output!
input == "y" or "Y" doesn't do what you think. Instead it evaluates to (input == "y") or ("Y"), what you want it input == "y" or input == "Y".
You needed to set loop to false when the input was either "y" or "Y" or "n" or "N", otherwise the loop would continue.
Fourthly setting the loop to true inside the loop is unnecessary, it begins as true, and the only change you can make is to set it to false. And since each of the conditions are mutually exclusive i.e input being "y" or "Y" mutually exclusive to input being "n" or "N" or it being neither "y" or "Y" or "n" or "N". You don't need to worry about it being set to false unless you wanted the loop to end.
local function check()
io.write"Continue? (Y/N): "
local ans, num = {y = 1, n = 2}
repeat
num = ans[io.read():lower()] or 3
io.write(({"Ok!\n","Fine...\n","Invalid Answer! Try again (Y/N): "})[num])
until num < 3
return num
end
print (check())

Resources