Manipulating table key

92 Views Asked by At

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

3

There are 3 best solutions below

0
shingo On BEST ANSWER

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
0
darkfrei On

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
0
user3204810 On

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]
}