glom
glom copied to clipboard
How to access more than one field without creating a dict?
Say I have the following data structure:
target = [{'a': 1, 'b': 1}, {'a': 2, 'b': 2}]
I want to create a spec that access both fields 'a' and 'b' at the same level, but instead of storing their values on a dictionary, I want to store on a tuple, so to achieve:
glom(target, spec) == [(1, 1), (2, 2)]
For example:
- Accessing as a dictionary (works, but this is not what I want):
spec = [{'a': 'a', 'b': 'b'}]
[{'a': 1, 'b': 1}, {'a': 2, 'b': 2}]
- Accessing in tuples (does not work):
spec = [('a', 'b')]
This does not work, as 'b' is interpreted as the spec of the next level, and not as a 'parallel' access at the same level.
I was able to obtain the desired result with:
spec = [({'a': 'a', 'b': 'b'}, lambda t: tuple(t.values())]
But I wonder if there is a more appropriate way? Thanks in advance!
It depends somewhat on whether you want to access all fields, or named subset.
For all fields, the lambda t: tuple(t.values()) method is the most appropriate (it could also be rewritten as Invoke(tuple).specs(T.values())).
If you want to access a specific, static set of fields however, then you could use the new Fill mode:
glom(target, [Fill((T['a'], T['b']))])
# or
glom(target, [Fill((Path('a'), Path('b')))])
Although truth be told, the way Fill actually works is rather different from what I understood it to be from the docs. My understanding was that this would work for what you're trying to do, but it doesn't:
# not the expected result
glom(target, [Fill(('a', 'b'))])
>>> [('a', 'b'), ('a', 'b')]