How can I replace an elseif chain with a table?

I want to know how to replace long elseif chains with a single table. I am making an an admin script, here is my current model.

if text == "kill" then 
cool stuff
elseif text == "teleport" then
cool stuff
elseif text == "kick" then
cool stuff
elseif text == "this is not really my script its just an example" then
blah blah blah, more elseifs.

I currently have 20+ elseifs, I want to learn how to convert them into a table before I make any more. Why do I want to do this? It looks cool, plus it is easier to read in my opinion. so, how do you make a table that replaces huge elseif chains?

1 Like

That’s a neat idea! I might use this in my own game!

Let’s make a 2D array called logicChain. This will hold our logic and respective results.

A conditional statement has two parts to it: a condition and a result. Let’s store those like this in the array: { {condition1, result1}, {condition2, result2}, … }

Now, we need a loop to go through the table and evaluate each condition. If we want to have an “else” statement at the end, we can just put it as the last entry in the table and have the condition just set to true, so it will execute if nothing else in the table does.

We also need to provide a noMatchResult in case none of our conditions match. nil seems intuitive to me in most cases, but sometimes you may need to use something else.

I believe the condition will evaluate as soon as you declare the logic table, so you need to re-create the table each time you call it.

function evaluateLogicTable(logicTable, noMatchResult)
  local logicTableEvalIndex = 1
  while (logicTableEvalIndex <= #logicTable) do
    if logicTable[logicTableEvalIndex][1] then
      return logicTable[logicTableEvalIndex][2]
    end
    logicTableEvalIndex = logicTableEvalIndex + 1
  end
  return noMatchResult
end

local x = 3
local logicTable = { {(x > 4), “X is greater than 4”}, {(x > 2), “X is greater than 2”}, {true, “An else condition if we want one”} }
print(evaluateLogicTable(logicTable, nil))
-- Will output “X is greater than 2”

local x = 5

print(evaluateLogicTable(logicTable, nil))
-- Will output “X is greater than 2”, since the original logicTable does NOT get re-evaluated until it gets reassigned

logicTable ={ {(x > 4), “X is greater than 4”}, {(x > 2), “X is greater than 2”}, {true, “An else condition if we want one”} }
print(evaluateLogicTable(logicTable, nil))
-- Will now output “X is greater than 4” as we expect since the conditions have been re-evaluated

———————————

To make life easier for you, just use a function that resets/re-evaluates your logic table every time you need it:

-- Updating by function call (RECOMMENDED)

function getMyLogicTable()
  return { {(x > 4), “X is greater than 4”}, {(x > 2), “X is greater than 2”}, {true, “An else condition if we want one”} }
end

logicTable = getMyLogicTable()



-- Updating by global variable

logicTable = nil

function getMyLogicTable()
  logicTable = { {(x > 4), “X is greater than 4”}, {(x > 2), “X is greater than 2”}, {true, “An else condition if we want one”} }
end

getMyLogicTable()

1 Like

Um… Anyways… I’m not too sure what’s going on but I assume its trying to find the best result given the dictionnary?

Here’s a much easier approach and probably the best.

You can just make a dictionnary with your text indexes and their functions as values like this.

local commands = {
    ['kill'] = function(...)
        print(...)
    end,
    ['teleport'] = function(...)
        print(...)
    end
}

if commands[text] then
    commands[text](args)
end

Or, alternatively you can turn this whole system modulary. Just by making a folder and adding all the commands in there. Then you loop through and index them all in an array and call them from there.

Quick example

local Commands = {}
for _, v in ipairs(CommandsFolder:GetChildren()) do
    Commands[v.Name] = require(v)
end

if Commands[text] then
    Commands[text]()
end
4 Likes

this is cool, I am a little confused on how the folder solution would work though. I do not know much about require, from what I understand it runs the code inside the script that you use it on. is this correct, and if it is correct does the folder version work by having a script for each command inside the folder?

does the folder version work by having a script for each command inside the folder?

Module scripts to be exact*


Well I’ll just summarize it quickly. But you can find more in depth explanations everywhere.

Modules are used to store DataTypes in them. Such strings, numbers, functions, booleants etc… In our case, we want to store a function so that we run that function every time we get text as a certain value.

In this module, we’re going to put something like this.

return function(...)
    print(...)
end

Where modules must absolutely return a value, or else it’s an invalid module. Here, we are returning a function, so when we require the module, we get it as a function we will run.
There are other ways of formatting the code, but this is my personal favorite. You can adapt in other ways of returning the function.

Let’s say the value of text is “eggroll”, well we would want to run the eggroll module.
image

Here’s how that would be used using my code above:

local Commands = {}
for _, v in ipairs(CommandsFolder:GetChildren()) do
    Commands[v.Name] = require(v)
end

local text = 'eggroll'
if Commands[text] then
    Commands[text]() -- will run the eggroll module
end

That’s probably all you need to know about modules. The rest should come in easily.

2 Likes

I like the idea of using ModuleScripts here a lot. A common inconvenience that can often be found in admin command systems is that people tend to stack every command definition in one script. This can lead to scripts that are more than 500 lines of code in size which is ridiculous and unreadable. ModuleScripts solve this problem by dividing each command definition in its own script.

Oh right, right. That is a struggle to debug, but you can always hold onto a Utility module nearby. Preferably outside of the folder, but somewhere easily accessible for both the modules and the script.

I probably interpreted your input incorrectly. Do you mean where people start using the same exact function names with the same task and copy paste that in each module? If so, then a utility module would be the best solution (imo).

What I mean is this:

local commands = {
   -- Now imagine that someone made over 200 commands in this table.
   -- Good luck with reading and understanding the entire script.
   test = function() print("hello") end,
}
1 Like

Yes, using a dictionary better fits the use case here, especially for something like string matching where you have a defined key.

Please note, the OP asked “how do you make a table that replaces huge elseif chains?”. That’s why I created a table that would be evaluated sequentially based on conditions placed in a table.

For example, let’s say you want to compare a value against a variable - “is x greater than 10?” You can’t use (x > 10) in a dictionary, because the key would just evaluate to true or false depending on the value of x, and you could have conflicting keys. (Even if that didn’t happen, dictionaries do not retain order, so it would not serve as a true elseif chain.)

I have faced times in my development where I may need lots of simple if/else conditions, where the conditions need to be evaluated and are not unique keys, where something like that may help and look cleaner.

3 Likes