Hi,
I would like to acess values of nested data structure with a Tuple
representing the fields location in the data structure. The data structure can be of an arbitrary type and depth. Here is a MWE illustrating a few operations I would like to perform.
data = (a = 1, b = (a = [4,2], b = 3))
k1 = (:a,)
k2 = (:b, :a, 1)
function get_value(data, k)
# get value at key k
end
# returns 1
get_value(data, k1)
# returns 4
get_value(data, k2)
Is there a way to achieve this? Is recursion the right approach?
Thanks!
A combination of dispatch and recursion would work:
get_value(data::NamedTuple, k::Symbol) = getproperty(data, k)
get_value(data::AbstractVector, k::Int) = getindex(data, k)
function get_value(data, k::Tuple)
if length(k) == 0
data
else
get_value(get_value(data, k[1]), k[2:end])
end
end
Alternatively, you could just use a loop:
function get_value2(data, ks)
for k in ks
data = get(data, k, missing) # get works for many types and handles missing keys
end
data
end
2 Likes
Can you give some context? What is the application, and how is the tuple of fields being generated?
Thank you for your replies.
@bertschi, thank you. I think your second approach will work.
@stevengj, the context is a bit difficult to describe without going into a rabbit hole. Basically, I am trying to compare values in two data structures. I know the “keys” of each, but not the values at those keys.
It’s not quite as bullet-proof as I had hoped for. A more rigorous solution might be using lenses from Accessors.jl:
julia> l1 = PropertyLens(:a) # describes path into data, i.e., like k1 = (:a,)
(@o _.a)
julia> l1(data)
1
julia> l2 = Accessors.opticcompose(PropertyLens(:b), PropertyLens(:a), IndexLens(1))
(@o _.b.a[1])
julia> l2(data)
4
1 Like
Thanks for the update! Accessors.jl looks like a relevant package.