2

This table is structured like this:

local t = {
        ["track"] = "one#two#three",
        {
            ["track"] = "four"
        }, -- [1]
}

The first step is to replace the "track" key with the "aura" key. For this purpose I created this function

local function probe(tbl)
    for k, v in pairs(tbl) do
        if type(v) == "table" then
            probe(v)
        elseif type(v) == "string" and k == "track" then
            tbl["aura"] = tbl[k]
            tbl[k] = nil
        end
    end
end

running the probe(t) command the table becomes

{
      ["aura"] = "one#two#three",
      {
          ["aura"] = "four",
      }, -- [1]
}

The second step consists in creating as many tables of the form { ["aura"] = word } as there are tokens in the string "one#two#three". For this purpose I created the function

local function updateDB(tbl, depth)
    if depth > 0 then    
        local d = depth    
        for k, v in pairs(tbl) do
            if type(v) ~= 'table' then                
                if k == 'aura' then
                    local count = 1
                    for word in v:gmatch(("[^%s]+"):format("#")) do
                        tbl[count] = { ["aura"] = word }
                        count = count + 1
                    end
                    tbl[k] = nil    
                end
            else 
                d = d - 1
                updateDB(v, d)
            end
        end
    end
end

The final table I get is this

{
      {
          aura= "one",
      }, -- [1]
      {
          aura= "two",
      }, -- [2]
      {
          aura= "three",
      }, -- [3]
}

But "four" value is gone away

9
  • 1
    You may not add new keys while traversing the table. Your probe function currently exhibits undefined behavior. Commented Oct 16, 2023 at 16:35
  • The function renames the "track" keys to "aura" keys Commented Oct 16, 2023 at 18:00
  • 1
    Yes, and you can't (as in, aren't allowed to, it will often work fine, but it you may run into problems when a rehash is triggered) do that while you're iterating the table. You should do it outside of the loop. Commented Oct 16, 2023 at 18:10
  • 1
    A bit awkward to post in a comment, but something like local function probe(tbl) for k, v in pairs(tbl) do if type(v) == "table" then probe(v) end end if type(tbl.track == "string") then tbl.aura = tbl.track; tbl.track = nil end end. May also be slightly more efficient :) Commented Oct 16, 2023 at 20:01
  • 1
    Oops, looks like I have a typo there. It should be type(tbl.track) == "string", otherwise you get type(tbl.track == "string") which will always be the string "boolean", which is truthy. Commented Oct 16, 2023 at 23:14

3 Answers 3

2

Because you started inserting elements from 1. To insert elements into empty slots, you can use either t[#t+1] or table.insert.

--local count = 1
for word in v:gmatch(("[^%s]+"):format("#")) do
    tbl[#tbl+1] = { ["aura"] = word }
    --count = count + 1
end
--local count = 1
for word in v:gmatch(("[^%s]+"):format("#")) do
    table.insert(tbl, { ["aura"] = word })
    --count = count + 1
end
Sign up to request clarification or add additional context in comments.

Comments

1

See this string separator: https://stackoverflow.com/a/1647577/12968803

The code by the link takes strings between separators (also both ends).

Update: The function returns the list, not iterator:

function string:split(pat)
    pat = pat or '%s+'
    local result = {}
    local st, g = 1, self:gmatch("()("..pat..")")
    local function getter(segs, seps, sep, cap1, ...)
        st = sep and seps + #sep
        table.insert(result, self:sub(segs, (seps or 0) - 1))
        return cap1 or sep, ...
    end
    local function iterate()
        if st then
            getter(st, g())
        end
        return result
    end
    while st do
        iterate()
    end
    return result
end

usage:

local str = "one#two#three"
local list = str:split("#")
for i, v in ipairs (list) do
    print (i, v)
end

result:

1   one
2   two
3   three

Comments

0

Fixed

Step one:

local t = {
        ["track"] = "one#two#three",
        {
            ["track"] = "four"
        }, -- [1]
}

local function probe(tbl) -- Rename "track" to "aura"
    for k, v in pairs(tbl) do 
        if type(v) == "table" then 
            probe(v)
        end 
    end
    if tbl.track then 
        tbl.aura = tbl.track
        tbl.track = nil 
    end
end

probe(t):now table becomes

{
      ["aura"] = "one#two#three",
      {
          ["aura"] = "four",
      }, -- [1]
}

Step two:

function updateDB(tbl, depth) 
    if depth > 0 then        
        for k, v in pairs(tbl) do
            if type(v) ~= 'table' then                
                if k == 'track' then
                    local count = 1
                    for word in v:gmatch(("[^%s]+"):format("#")) do
                        table.insert(tbl,{ ["aura"] = word })
                        count = count + 1
                    end
                    tbl[k] = nil    
                end
            else 
                updateDB(v, depth-1)
            end
        end
    end
end

updateDB(t,1): now table becomes

{
      {
          aura= "one",
      }, -- [1]
      {
          aura= "two",
      }, -- [2]
      {
          aura= "three",
      }, -- [3]
      {
          aura= "four",
      }, -- [3]
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.