Page 1 of 1

String to access nested table value.

Posted: Mon Apr 19, 2021 3:17 pm
by VEXED
The question I have is more of a Lua specific question, so hopefully I am alright to ask here.

Lua has two main ways of accessing a key in a table that I know of.

Code: Select all

local t = {x=0, y=5, other={z=10}}

-- Both should print "0"
print(t["x"])
print(t.x)

-- "x" can also be a variable
local prop = "x"
-- First prints "0". Second prints "nil"
print(t[prop])
print(t.prop)
This all works fine and is simple enough, but I am wanting to do a nested access with a single . seperated string.

Code: Select all

local t = {x=0, y=5, other={z=10}}
local zprop = "other.z"

-- This prints "nil"
print(t.zprop)
I'm sure I could loop through and seperate each . seperated value into a table. Then loop that to access the value, but I was wondering if a more sane way of doing this existed.

Thanks for any advice.

Re: String to access nested table value.

Posted: Mon Apr 19, 2021 3:33 pm
by GVovkiv

Code: Select all

local t = {x=0, y=5, other={z=10}}
local zprop = "other"

-- This prints 10
print(t[zprop].z)

Re: String to access nested table value.

Posted: Mon Apr 19, 2021 4:31 pm
by VEXED
GVovkiv wrote: Mon Apr 19, 2021 3:33 pm

Code: Select all

local t = {x=0, y=5, other={z=10}}
local zprop = "other"

-- This prints 10
print(t[zprop].z)
Thanks for the reply.

This isn't what I'm asking. I want to combine multiple keys into one string and access a nested table key with a single string. That or parse a string to access them.

In your example I still have to go in and specify the key of "z". Rather I want to just put all of that into one string of "other.z"

Re: String to access nested table value.

Posted: Mon Apr 19, 2021 5:07 pm
by pgimeno
There isn't a direct route. At best, you can make a function to do this kind of access, but it's not the path I'd recommend to follow:

Code: Select all

local function nested(table, index)
  for s in index:gmatch("[^%.]+") do
    table = table[s]
  end
  return table
end

local t = {x=0, y=5, other={z=10}}
local zprop = "other.z"

print(nested(t, zprop)) -- prints 10
I'd advise you to look for alternatives. It's not immediately clear what your plans are, so I can't suggest any.

Re: String to access nested table value.

Posted: Mon Apr 19, 2021 5:08 pm
by grump
VEXED wrote: Mon Apr 19, 2021 3:17 pm but I was wondering if a more sane way of doing this existed.
We could have a talk about your definition of "sane" now, but I have this instead:

Code: Select all

local function sanelookup(t, path)
    for s in path:gmatch('[^.]+') do
        t = t[s]
    end
    return t
end

local t = {x=0, y=5, other={z=10}}
local zprop = "other.z"
print(sanelookup(t, zprop))
There are ways to automate this for selected tables, but I would strongly object to any of that.

edit: damn ninjas

Re: String to access nested table value.

Posted: Mon Apr 19, 2021 11:09 pm
by VEXED
pgimeno wrote: Mon Apr 19, 2021 5:07 pm There isn't a direct route. At best, you can make a function to do this kind of access, but it's not the path I'd recommend to follow:

I'd advise you to look for alternatives. It's not immediately clear what your plans are, so I can't suggest any.
Hey, thanks a bunch this was very useful. Also thanks grump.

I'm now realizing that a "nested" table setter is something that I need as well (this seems 10x more confusing to do). Let me provide some explanation of what I'm attempting as to hopefully get some more clear direction on what to do.

My application takes in json that defines basics of "objects" in my app. This JSON is converted to a table, and then the code is highly generic code for handling some of these table values. Let me give an example here.

Code: Select all

{
  "object": {
    "width": 32,
    "height": 32,

    "position": {
      "x": 128,
      "y": 128
    },

    "movement": {
      "vvel": 0,
      "hvel": 0,
      "hspd": 4,
      "vspd": 4
    },

    "held": {
      "up": {"movement.vvel": -1},
      "down": {"movement.vvel": 1},
      "left": {"movement.hvel": -1},
      "right": {"movement.hvel": 1}
    }
  }
}
I just stripped a lot of values from the JSON above, so hopefully I haven't botched the syntax.

Anyhow, the main thing to focus on is the "held" table. I have designed a few tables that my code deals with for key press, hold, and release. They work fine but the problem I'm having is using them to set nested values. As seen above I am trying to set values in the tables movement sub table. This is a string I would like to handle in my games logic that parses through to my table above's specified value and sets it.

It works fine when say modifying the width that isn't in a sub table. Once I get to this nested issue it becomes quite nasty to deal with.

This might be different enough from the original topic to warrant a new topic, but i'll post here first.

Re: String to access nested table value.

Posted: Tue Apr 20, 2021 5:57 am
by grump

Code: Select all

local function saneset(t, path, value)
    local p, k
    for s in path:gmatch('[^.]+') do
        k, p, t = s, t, t[s]
    end
    p[k] = value
end
Can I ask where those JSON files come from? Are you writing them by hand?

Re: String to access nested table value.

Posted: Tue Apr 20, 2021 10:24 am
by pgimeno
It's weird to have movement defined in such a file. Usually, movement needs custom logic - handling collisions, at least. There may be types of movements that you handle separately, but I'd rather have a field "movement_type" or something like that for these cases. Then your code would have the movement part hardcoded. Like, if you call this "straightforward", the implementation could be similar to this:

Code: Select all

if object.movement_type == "straightforward" then
  object.movement.hvel = 0
  object.movement.vvel = 0
  if held("up") then
    object.movement.vvel = object.movement.vvel - 1
  end
  if held("down") then
    object.movement.vvel = object.movement.vvel + 1
  end
  if held("left") then
    object.movement.hvel = object.movement.hvel - 1
  end
  if held("right") then
    object.movement.hvel = object.movement.hvel + 1
  end
elseif object.movement_type == "another type" then
  ...
end

Re: String to access nested table value.

Posted: Tue Aug 01, 2023 9:51 pm
by jcarballo
Today I came up with this solution:

Code: Select all


a = { b = 2 }

get_nested_value = function(value)
    local ok, _ = pcall(function() return value end)
    return ok and value or nil
end

b = get_nested_value(a.b) -- 2
c = get_nested_value(a.c) -- nil