I have the following highly simplified structure
elements = [{"id": "1", "counts": [1, 2, 3]},
{"id": "2", "counts": [4, 5, 6]}]
I'd like to be able to construct, using glom
, a new dictionary of the form {<id>: <counts[pos]>}
, eg for pos = 2
:
{"1": 3, "2": 6}
or alternatively a list/tuple of tuples
[("1",3), ("2", 6)]
Using a dict comprehension
is easy, but the data structure is more complicated and I'd like to dynamically specify what to extract. The previous example would be the simplest thing I'd like to achieve.
After a while I managed to solve it as follows
from glom import glom, T
elements = [{"id": "1", "counts": [1,2,3]},{"id": "2", "counts": [4,5,6]}]
def extract(elements, pos):
extracted = glom(elements, ({"elements": [lambda v: (v["id"], v["counts"][pos])]}, T))
return dict(extracted["elements"])
But this requires a call to dict
. A slight variation that skips a dictionary indirection would be
def extract(elements, pos):
extracted = glom(elements, (([lambda v: {v["id"]: v["counts"][pos]}]), T))
return {k: v for d in extracted for k, v in d.items()}
Now, I could use the merge
function called onto the returned values from the glom
call
def extract(elements, pos):
return merge(glom(elements, (([lambda v: {v["id"]: v["counts"][pos]}]), T)))
I'm rather satisfied with this, but is there a better approach to do this? And with better I mean building a single cleaner spec callable? Ultimately, I'd like to be able to define at runtime in a user friendly way the values of the dictionary, ie, v["counts"][pos]
.
An improvement towards this idea would be to use a callable to be invoked for the value of the internal dictionary
def counts_position(element, **kwargs):
return element["counts"][kwargs["pos"]]
def extract(elements, func, **kwargs):
return merge(glom(elements, (([lambda v: {v["id"]: func(v, **kwargs)}]), T)))
extract(values, counts_position, pos=2)
With this, what's begin extracted from each element can be controlled externally.
To convert a list of dicts with id
in each one to an id-keyed dict you could use a simple dict comprehension:
{t["id"]: glom.glom(t, "counts.2") for t in elements}
Or, if you want to use glom for that, use glom.Merge
along with glom.T
:
glom.glom(elements, glom.Merge([{T['id']: 'counts.2'}])))
To avoid lambdas, you could interpolate the pos
param into the spec string, eg 'counts.%s' % pos
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.