Form for choosing settings I've created a form to choose the settings: These settings are automatically saved in a file from the game client in this form:

["Setting"] = {
    ["track"] = "Spell Reflect",
    ["duration"] = {
        ["minimum"] = {
            ["enabled"] = 1,
            ["value"] = 3,
        },
        ["maximum"] = {
        },
    },
    ["stack"] = {
        ["minimum"] = {
        },
        ["maximum"] = {
            ["enabled"] = 1,
            ["value"] = 4,
        },
    },
}


To save the settings in this form I used this function:

function UnitScan_onAdvancedOptionClose()
    if not (db["duration"]) then 
        db["duration"] = {}
        db["duration"]["minimum"] = {}
        db["duration"]["maximum"] = {}
    end
    db["duration"]["minimum"].enabled = minduration.cbutton:GetChecked()
    db["duration"]["minimum"].value = tonumber(minduration.ebox:GetText())
    db["duration"]["maximum"].enabled = maxduration.cbutton:GetChecked()
    db["duration"]["maximum"].value = tonumber(maxduration.ebox:GetText())

    if not (db["stack"]) then 
        db["stack"] = {}
        db["stack"]["minimum"] = {}
        db["stack"]["maximum"] = {}
    end
    db["stack"]["minimum"].enabled = minstack.cbutton:GetChecked()
    db["stack"]["minimum"].value = tonumber(minstack.ebox:GetText())
    db["stack"]["maximum"].enabled = maxstack.cbutton:GetChecked()
    db["stack"]["maximum"].value = tonumber(maxstack.ebox:GetText())
end


Where


db = The "Setting" table
GetChecked() = Returns whether the check button is checked
GetText() = Returns the edit box's text contents


Could you help me to make the code less repetitive and more elegant?
One big thing we need to do is to sort everything into arrays

I should point out that

db.stack


is the same as

db["stack"]


Firstly, shift GetChecked() and GetText() (sidenote functions names usually start with lowercase) into an array

local get = { maximum = GetChecked, minimum = GetText }


Stuff that needs to be called during min should be given the "minimum" key. Same with "maximum".

Sort everything else out...

local func = { minimum = "cbutton", maximum = "ebox"}
local keys = {"enabled", "value"}
local minmax = {"minimum", "maximum"}
local db = {}
local stuff = {"stack", "duration"}
local minormax = { minimum = "min", maximum = "max" }


Lets take a break for a second, and create the important array

for _, each in ipairs(stuff) do
  db[each] = {}
  for _, it in ipairs(minmax) do
    db[each][it] = {}
  end
end


This creates

db["stack"]["minimum"]
db["stack"]["maximum"]
db["duration"]["minimum"]
db["duration"]["maximum"]


Now first, we iterate over the stack and duration keys

for _, param in ipairs(stuff) do

end


Then we iterate over the min max values

for _, param in ipairs(stuff) do
  for _, min_max in ipairs(minmax) do

  end
end


Then we iterate over enabled and value

for _, param in ipairs(stuff) do
  for _, min_max in ipairs(minmax) do
    for _, key in ipairs(keys) do

    end
  end
end


To recap, for both the stack and duration, we are checking min and max, and for both min and max, we are checking enabled and value. So your function looks something like this:

db[param][min_max][key] = _G[minormax[min_max]..param][func[min_max]]:get[min_max]()


Finally, we iterate over all the min entries to tonumber them

for _, each in ipairs(db) do
  for _, it in ipairs(db[each]["minimum"]) do
    db[each]["minimum"] = tonumber[each]["minimum"]
  end
end


Let's consolidate everything:

local func = { minimum = "cbutton", maximum = "ebox"}
local get = { maximum = GetChecked, minimum = GetText }
local keys = {"enabled", "value"}
local minmax = {"minimum", "maximum"}
local db = {}
local stuff = {"stack", "duration"}
local minormax = { minimum = "min", maximum = "max" }

for _, each in ipairs(stuff) do --Create the multidimensional array
  db[each] = {}
  for _, it in ipairs(minmax) do
    db[each][it] = {}
  end
end

for _, param in ipairs(stuff) do --The important function
  for _, min_max in ipairs(minmax) do
    for _, key in ipairs(keys) do
      db[param][min_max][key] = _G[minormax[min_max]..param][func[min_max]]:get[min_max]()
    end
  end
end

for _, each in ipairs(db) do --Tonumber all the min entries
  for _, it in ipairs(db[each]["minimum"]) do
    db[each]["minimum"] = tonumber([each]["minimum"])
  end
end


Sorry for the long answer. Hopefully it works, because with such a complicated program my poor brain had to work it out slowly and methodically. The different steps should help you understand my train of thought and help you flush out any bugs (if there are any)

I cannot guarantee this solution will work (I may have messed up somewhere), and it looks really repetitive in itself but here you go.

EDIT: I noticed some of the code is missing. I'll fill in the rest when I have time

EDIT 2: I changed some of the code after reviewing it again.

EDIT 3: Thank you Etan Reisner for pointing out the mistakes I made. I've edited the code.

EDIT 4: You can actually combine the array creation loop and the main body loop if you want:

for _, param in ipairs(stuff) do --The important function
  db[param] = {}
  for _, min_max in ipairs(minmax) do
    db[param][min_max] = {}
    for _, key in ipairs(keys) do
      db[param][min_max][key] = _G[minormax[min_max]..param][func[min_max]]:get[min_max]()
    end
  end
end