Home > database >  Best way to have string key tables in order by how they were put in the code, in Lua
Best way to have string key tables in order by how they were put in the code, in Lua

Time:07-15

To clarify what I am trying to say, I have an example here:

local exampleTable = {
    ["Key_A"] = {
        
    },
    
    ["Key_B"] = {

    },
    
    ["Key_D"] = {

    },

When looping through these, it is not said that they will exactly appear in the same order like how it is in the code. However, I am trying to achieve that it appears like in the same order of the code. Independent on how the keys are named.

 

I am looking for a better way, for the flexibility. Better than the examples below, if there are even any better ones.

An example.

local differentExample = {
    {"Key_A"},
    {"Key_B"},
    {"KEY_D"},
}

Here, the keys use numbers as their index, exactly like how it was put in the code. You can easily add anything else inbetween the content of the table, without having to worry about the order, as it will automatically index it for you, but as a number.

I can easily add Key_C as position 3:

local differentExample = {
    {"Key_A"},
    {"Key_B"},
    {"Key_C"},
    {"KEY_D"},
}

 

So, I tried to come up with solutions.

local differentExample = {
    {
        ID = "Key_A",
    },
    
    {
        ID = "Key_B",
    },
    
    {
        ID = "Key_D",
    },
}

Here the keys do indeed get sorted by numbers based on the current order in the code. Allowing me to add "Key_C" inbetween "Key_B" and "Key_D"

The issue here is, I am not able to easily index these keys. I am forced to loop through all the entries in the table and match it by the ID. And I don't think this is an optimal solution at all.

 

Then there's this:

local differentExample = {
    ["Car"] = {
        Order = 1
    },

    ["Train"] = {
        Order = 2
    },

    ["Key_D"] = {
        Order = 3
    },
}

Here, you're able to tell what order it is. Here it probably doesn't matter if you have to loop through all of them and then get the Order value, to set the order of something.

However, the issue here is that if you want to add something inbetween the entries, you are forced to manually edit "Order"

local DominoStones = {
    ["DominoStone_A"] = {
        Order = 1
    },

    ["DominoStone_B"] = {
        Order = 2
    },

    ["DominoStone_D"] = {
        Order = 3
    },
}

If I would want to add a string key at the first order, I end up having to change all of the "Order" values below it.

local DominoStones = {
    ["DominoStone_Special"] = {
        Order = 1
    },
    
    ["DominoStone_A"] = {
        Order = 1 -- I have to change this to 2
    },

    ["DominoStone_B"] = {
        Order = 2 -- I have to change this to 3
    },

    ["DominoStone_D"] = {
        Order = 3 -- I have to change this to 4
    },
}

So this is the worst solution for this problem.

 

 

The only best solution that I know, is this:

local orderedKeys = {
    "Key_A",
    "Key_B",
    "Key_D"
}

local exampleTable = {
    ["Key_A"] = {

    },

    ["Key_B"] = {

    },

    ["Key_D"] = {

    },
}

Here you can use the orderedKeys to loop through the string keys.

However, still not perfect enough, because if you want to add a new string key in the exampleTable you also have to add it to the orderedKeys table.

So still not ideal.

 

The custom print table functions don't solve the issue either, like the Garry's Mod or Roblox one. They use table.sort to sort it alphabetically and then print it out, so don't get confused by that.

 

So I am looking for better solutions. What are the better solutions?

I came up with something here: https://stackoverflow.com/a/72985494/11161500

Not sure if it is the best solution.

CodePudding user response:

Another solution: Write yourself an utility to do this for you! The simplest way would be a function that adds an entry:

local order, map = {}, {}
local function add_entry(key, value)
    table.insert(order, key)
    map[key] = value
end
add_entry("KeyA", {})
add_entry("KeyB", {})
add_entry("KeyC", {})

or if you want it more compact:

local function add_entries(key, value, ...)
    if key == nil then return end
    add_entry(key, value)
    return add_entries(...)
end
add_entries("KeyA", {}, "KeyB", {}, "KeyC", {})

obviously you could also write yourself an utility to take a nested table structure {{"KeyA", {}}, {"KeyB", {}}, {"KeyC", {}} if you want a LISP-y vibe (downside: creates unnecessarily many garbage tables).

(fun fact: this is how you usually initialize maps in Java - by calling put)

CodePudding user response:

Something I just came up with, was this:

local order = 0
function getOrder()
    order  = 1
    
    return order
end

local exampleTable = {
    ["Key_A"] = {
        Order = getOrder()
    },

    ["Key_B"] = {
        Order = getOrder()
    },

    ["Key_D"] = {
        Order = getOrder()
    },
}

This indeed sets the value of "Order" based on the order on how it is in the code. But I am not really sure how ideal this is supposed to be. Or how flexible it would be. Let's say you would try to add "Key_C" in between "Key_B" and "Key_D", while the code itself is running already.

Without overriding the entire table and reinitializing order back to 0, it wouldn't give the wanted result.

  • Related