4

Can anyone help me figure the list comprehension way of producing following output -

Let given list be -

results = [
    {"id":  1, "name":  "input"},
    {"name": "status", "desc": "Status"},
    {"name": "entity", "fields": [
        {"id": 101, "name": "value"},
        {"id": 102, "name": "address"}]
    }
]

And I am looking for output in the form of list. The code to get the output is:

output = []
for eachDict in results:
    if "fields" in eachDict:
        for field in eachDict["fields"]:
            output.append(eachDict["name"]+"."+field["name"])
    else:
        output.append(eachDict["name"])

Thus the output using above code is -

['input', 'status', 'entity.value', 'entity.address']

Is it possible to get similar output using if else nested for loops in list Comprehension?

I am having trouble trying to get access to that inner for loop in if condition of list Comprehension

My attempt -

output = [eachDict["name"]+"."+field["name"] for field in eachDict["fields"] if "fields" in eachDict else eachDict["name"] for eachDict in results]
1
  • This will work, but is not good code, to make it more readable delegate tasks to functions... [item for sublist in [['{0}.{1}'.format(d['name'], f['name']) for f in d['fields']] if 'fields' in d else [d['name']] for d in results] for item in sublist] Commented Jul 6, 2017 at 16:23

2 Answers 2

7

One way to transform your code into workable code would be to make the inner loop produce lists, and then flatten the result afterward.

sum(([d['name'] + '.' + f['name'] for f in d['fields']] 
    if d.get('fields') else [d['name']] for d in results), [])
Sign up to request clarification or add additional context in comments.

Comments

3

A list comprehension has a fixed number of (nested) loops. So must have two loops here, one over the top-level dictionaries, and one over the fields. The trick is to produce one iteration in the nested loop if there are no fields:

[d['name'] + fieldname 
 for d in results
 for fieldname in (
    ('.' + sub['name'] for sub in d['fields']) if 'fields' in d else
    ('',))
]

The for fieldname loop loops either over the names of the fields sub-directories (with '.' prefixed), or over a tuple with just a single empty string in it.

Note that this isn't actually all that readable. I'd delegate producing the fieldname loop to a helper generator function to improve that:

def fieldnames(d):
    if 'fields' in d:
        for sub in d['fields']:
            yield '.' + sub['name']
    else:
        yield ''

[d['name'] + fieldname for d in results for fieldname in fieldnames(d)]

Demo:

>>> def fieldnames(d):
...     if 'fields' in d:
...         for sub in d['fields']:
...             yield '.' + sub['name']
...     else:
...         yield ''
...
>>> [d['name'] + fieldname for d in results for fieldname in fieldnames(d)]
['input', 'status', 'entity.value', 'entity.address']

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.