What is the alternative for switch statement in Lua language?
Asked Answered
G

11

25

I have this piece of code in C++ and i want to know how can i write some codes that replace switch statement in Lua because i face many problems and i need to use this statement.

int choice;
do // loop
{
    cout<<"\n >>> The General Menu <<< \n";
    cout << endl;
    cout<< " press (1) to Add    "<<endl;
    cout<< " press (2) to Save   "<<endl;
    cout<< " press (3) to Quit " << endl;
    cout<< endl;
    cout<< "Enter your choice please (1/2/3): ";
    cin>>choice;

    switch(choice)
    {
        case 1: 
            add();
            break;
        case 2:
            save();
            break;
            
        default:
            cout<<" The program has been terminated "<<endl;
            cout<<" Thank you! \n";         
    }   
} while (choice != 3);

The statement has been used inside a do..while loop.

Glyph answered 25/5, 2016 at 21:12 Comment(1)
2015 list of answers at lua-users.orgRighteous
I
30

In general, if you want a switch statement in Lua, what you ought to be doing is building a table. For your simple case of choice that could be 1, 2, or fail, a simple if statement with a few conditions is sufficient. For more complex cases, a table of functions should be employed:

local c_tbl =
{
  [1] = add,
  [2] = save,
}

local func = c_tbl[choice]
if(func) then
  func()
else
  print " The program has been terminated."
  print " Thank you!";
end

You can use lexical scoping to allow the functions in the table to be able to access local variables, just as if the code was written inline.

Infant answered 27/5, 2016 at 22:18 Comment(1)
Thanks @Nicol this is what i was looking for. I intended to build a table than using if..then..elseif statement. It's now working.Glyph
S
13

Try this one (click here to run the script in a Lua compiler), Hope the code is self-explanatory ;-) and

resembles the same pseudo code format..!!

print("enter your choice : ")
mychoice = io.read()

switch = function (choice)
  -- accepts both number as well as string
  choice = choice and tonumber(choice) or choice     -- returns a number if the choic is a number or string. 

  -- Define your cases
  case =
   {
     [1] = function ( )                              -- case 1 : 
             print("your choice is Number 1 ")       -- code block
     end,                                            -- break statement

     add = function ( )                              -- case 'add' : 
             print("your choice is string add ")     -- code block
     end,                                            -- break statement

    ['+'] = function ( )                             -- case '+' : 
             print("your choice is char + ")         -- code block
     end,                                            -- break statement

     default = function ( )                          -- default case
             print(" your choice is din't match any of those specified cases")   
     end,                                            -- u cant exclude end hear :-P
   }

  -- execution section
  if case[choice] then
     case[choice]()
  else
     case["default"]()
  end

end
-- Now you can use it as a regular function. Tadaaa..!!
switch(mychoice)
Spannew answered 14/10, 2017 at 4:23 Comment(0)
G
8

Lua:

if choice == 1
then add()
elseif choice == 2
then save()
else print "The program has been terminated\nThank you!"
end 
Gelatin answered 25/5, 2016 at 21:16 Comment(1)
Or (({add, save})[choice] or bye)()Grudge
D
4

While simply creating a table indexed by cases with functions as elements is most probably the fastest approach, there is this solution I've made which IMO has better code readability:

function switch(element)
  local Table = {
    ["Value"] = element,
    ["DefaultFunction"] = nil,
    ["Functions"] = {}
  }
  
  Table.case = function(testElement, callback)
    Table.Functions[testElement] = callback
    return Table
  end
  
  Table.default = function(callback)
    Table.DefaultFunction = callback
    return Table
  end
  
  Table.process = function()
    local Case = Table.Functions[Table.Value]
    if Case then
      Case()
    elseif Table.DefaultFunction then
      Table.DefaultFunction()
    end
  end
  
  return Table
end

Example Use:

switch(Player:GetName())
  .case("Kate", function() print("This player's name rhymes with Fate")end)
  .case("Tod", function() print("This player's name rhymes with Cod") end)
  .default(function() print("This player's name is not Kate or Tod") end)
  .process()
Dup answered 28/11, 2020 at 8:45 Comment(0)
E
3

one more version of switcher (without initializing table as variable):

local case=2;
local result=({[1]="case1", [2]="case2", 3="case3"})[case];
print (result); --> case2
Entozoon answered 8/6, 2017 at 22:8 Comment(0)
P
2

I encountered this issue with functions that would take different parameters - something which the other answers don't handle well.
I solved that with anonymous functions.

-- call the relevant execution based on its opcode
local instructions = {
    [01] = function () self:perform_add(table.unpack(valargs)) end,
    [02] = function () self:perform_multiply(table.unpack(valargs)) end,
    [03] = function () self:perform_store_input(outputargs[1]) end,
    [04] = function () self:perform_output(valargs[1]) end,
    [05] = function () self:perform_jnz(table.unpack(valargs)) end,
    [06] = function () self:perform_jz(table.unpack(valargs)) end,
    [07] = function () self:perform_less_than(table.unpack(valargs)) end,
    [08] = function () self:perform_equals(table.unpack(valargs)) end,
    [99] = function () self:perform_exit() end,
}
local instr = instructions[opcode]
if (instr) then
    instr()
else
    print("No instruction for opcode " .. opcode)
end

The actions I want to take in my different switch cases are all defined as anonymous functions in a table. The keys used (e.g. 08 here) are the values our variable to switch on might assume (opcode here). The default case of the switch statement happens in my else clause. There is no requirement for a break equivalent - but if you want to have one case continue with the next you would have to call it explicitly.


Reply to comment asking for clarification:

You're right that this example is not complete. You can find my usage here when I did adventofcode 2019 day 7. I can try answer your questions but I never touched lua before, and never after. valargs is a table of arguments because different functions here take different numbers of arguments. But that is not necessarily relevant to the question. Basically, I'm just calling functions here.

In my example, self exists because I defined the functions on a local (and did some weird changes as outlined here). The relevant code parts:

-- a "class"
local IntComputer = {}

    function IntComputer:perform_exit()
        self.program_ended = true
    end

    function IntComputer:perform_add(a, b, target)
        print("    " .. a .. " + " .. b .. " => " .. target)
        self:set_value(target, a+b)
    end
Presidentelect answered 13/4, 2020 at 21:24 Comment(5)
This code does not appear to do anything useful. opcode is not defined. And if I choose a value for it, Lua reasonably enough complains that self is not defined. Also, what is valargs?Impediment
@FaheemMitha you're correct that my answer leaves these infos out - they are not relevant to the question. But I've added more information to the end of my answer anyway now. I hope this is sufficient for your curiosity, because I don't remember much of this code.Presidentelect
Hi @lucidbrod. Thank you for taking the trouble to update your answer. Really, I was just looking for self-contained, runnable code that I could execute and modify as necessary. But if you don't remember, don't worry about it.Impediment
@FaheemMitha this answer basically suggest the same thing as mine. Maybe their code is runnable as-is :)Presidentelect
Thanks, lucidbrot. Yes, that answer was indeed runnable and useful.Impediment
W
1

If you want switch as a function that is callable, you could use something funny with the callback feature:

(The example below is a switch statement based on the variable type, but you could make the table index into whatever you want to test it for. Just change the return statement of the switch function to not test for type(case))

(This is essentially a lazy table lookup much like Python's dictionary feature but each element is a function)

#!/usr/bin/lua
-- Callback switch statement:
local function switch(a, case)
  -- Local variable instead of function(a) on every case:
  local value = a
  -- Cases list:
  local switchcase = {}

  -- Cases:
  switchcase["string"] = function()
    return (tostring(value) .. " is a string")
  end

  switchcase["number"] = function()
    return tostring(value .. " is a number")
  end

  switchcase["boolean"] = function()
    return (tostring(avalue) .. " is a boolean")
  end

  return switchcase[type(case)](a)
end

local value = 5
print(switch(value,value)) --> 5 is a number

local value = "test"
print(switch(value,value)) --> test is a string

local value = true
print(switch(value,value)) --> true is a boolean

I don't know the performance of this code compared to the two answers given above, but using local variables ought to make it quick enough for repeated use. If you make your switch function in the global scope it could become a standard function for your project to be used.

Wolfy answered 9/12, 2016 at 8:39 Comment(3)
I ran some tests on the answers in this question.Wolfy
I ran some tests on the answers: My local switch function: average: 63 ms in 100000 repetitions. The if, elseif solution: 22 ms The table choice solution: 58 ms. Keywords win the day again.Wolfy
And if you convert local function switch to a global switch, the results is average: 62 ms.Wolfy
W
1

Here's another fun method using loadstring() and a table lookup.

switch = function(cases,args)
  if (cases[args] == nil) then return args else return assert(loadstring ('return ' .. cases[args]))() end
end

local case = 2

local result = switch({
  [1] = "2^" .. case,
  [2] = string.format("2^%i",case),
  [3] = tostring(2^case)
},
case
)
print(result) --> 4

This method is somewhat dangerous to use since loadstring() is similar to Python's eval() function.

I found it ugly to write "function(x)" on every case in the examples provided by the Lua wiki. This is a neat way.

The "default" case is the "return args" part of the function.

Wolfy answered 20/12, 2016 at 8:57 Comment(0)
B
1
local myVar = "1"

function switchCase(result,tables)
    if tables[result] then
        if type(tables[result]) == "function" then
            return tables[result] ()
        else
            return tables[result]
        end
    end
    if tables["_"] then
        if type(tables["_"]) == "function" then
            return tables["_"] ()
        else
            return tables["_"]
        end
    end
    return nil
end

print (switchCase(myVar,{
  ["1"] = "result1",
  ["_"] = "result2",
}))
Brno answered 29/8, 2023 at 19:55 Comment(0)
R
0

I use this code :

while true do local tmpswitch1 = exp ; --[[ switch <exp> do ]]
    if tmpswitch1 == exp1 then --[[ case <exp1> : ]]
        -- do something
        break
    end ;if tmpswitch1 == exp2 then --[[ case <exp2> : ]]
        -- do something
        break
    end ; --[[ default : ]]
        -- do something
break ; end --[[ switch tmpswitch1 ]]
Rog answered 14/10, 2020 at 9:51 Comment(0)
B
0
function case(i,d) return function(t) return t[i] or d end end

x='two'

r=case(x) {
 one=1,
 two=2,
 three=3,
}

case(r,function() print "default" end) {
  [1]=function() print "one" end,
  [2]=function() print "two" end,
  [3]=function() print "three" end,
}()
Batangas answered 29/9, 2021 at 21:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.