简体   繁体   中英

Extracting fields of a list of dictionaries into a new dictionary using glom

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM