1

I've got an object that looks something like this:

obj = {
    "outer_list": [
        {
            "inner_list_1": ["string1", "string2"]
        },
        {
            "inner_list_2": ["string3", "string4"]
        }
    ]
}

I want to create a new list that is the combination of both inner lists:

["string1", "string2", "string3", "string4"]

Currently, I've got something like this:

result = []
for inner_object in obj['outer_list']:
    for my_str in inner_object['inner_list']:
        result.append(my_str)

I'm wondering how to write that nested loop in a single line.

result = [...]
1
  • It can be done in a single line but it's gonna be unreadable. Commented Aug 20, 2019 at 19:51

7 Answers 7

1

You can use itertools.chain.from_iterables:

from itertools import chain
list(chain.from_iterable(d['inner_list'] for d in obj['outer_list']))

So that given:

obj = {
    "outer_list": [
        {
            "inner_list": ["string1", "string2"]
        },
        {
            "inner_list": ["string3", "string4"]
        }
    ]
}

This returns:

['string1', 'string2', 'string3', 'string4']

Or if you want a solution for the data you posted in the question, where the key to the inner list in each sub-dict ends with an incremental number starting from 1, you can use enumerate to generate such incremental numbers:

list(chain.from_iterable(d['inner_list_%d' % n] for n, d in enumerate(obj['outer_list'], 1)))

So that given:

obj = {
    "outer_list": [
        {
            "inner_list_1": ["string1", "string2"]
        },
        {
            "inner_list_2": ["string3", "string4"]
        }
    ]
}

This returns:

['string1', 'string2', 'string3', 'string4']
Sign up to request clarification or add additional context in comments.

4 Comments

There're different keys, it's not inner_list.
The real question asked by the OP is how the nested loop can be rewritten into a single line, and that nested loop has a fixed key for the sub-dicts.
Very nice solution! Regarding the different keys, you can still replace it with double loop over dictionary values and it'll work for any example with static dictionary schema: list(chain.from_iterable(val for d in obj['outer_list'] for val in d.values()))
I've updated my answer with a solution for the given input data from the OP, where keys for the inner lists end with incremental numbers.
0

The nested notation in Python is the most weird i ever seen. Its construction [x for y in z for x in y]

result = [ my_str for  inner_object in obj['outer_list'] for my_str in inner_object ['inner_list']]

1 Comment

The inner lists are numbered: inner_list_1 and inner_list_2. Trying feed in the key inner_list doesn't work.
0

If I HAD to do it in one line, I'd probably do it like this.

import itertools
result = list(itertools.chain.from_iterable([tuple(el.values())[0] for el in d['outer_list']]))

yields

['string1', 'string2', 'string3', 'string4']

But the solution you already came up with is much better.

Comments

0

Try this :

result = []
for inner_object in obj['outer_list']:
    for k in inner_object:
        result.extend(inner_object[k])

Here is an one-liner :

result = [i for inner_object in obj['outer_list'] for v in inner_object.values() for i in v]

Output :

['string1', 'string2', 'string3', 'string4']

Comments

0

You can use comprehension to do it, but it runs some risks depending on the inner objects:

resultList = [ stringVal for stringVal in x for x in y.values() for y in obj['outer_list']]
>>> resultList
['string3', 'string3', 'string4', 'string4']

1 Comment

You have to go from largest to smallest, not smallest to largest: [ stringVal for y in obj['outer_list'] for x in y.values() for stringVal in x]
0

You can use reduce to achieve this

from functools import reduce
result = list(reduce(lambda x,y: x['inner_list']+y['inner_list'], obj['outer_list']))

Comments

0

[item for inner_dict in obj["outer_list"] for item in list(inner_dict.values())[0]]

A list comprehension is made up of two things: an expression, and a loop. You can think of a list comprehension being made as being shorthand for list(get_items()), where get_items is defined as

def get_items():
       loop:
            yield(expression)

In this case, loop is

       for inner_dict in obj["outer_list"]:
           for item in list(inner_dict.values())[0]:

and expression is item.

So, the format for the list comprehension is to first write what's being yielded (in this case, item), then writing the loop that is iterated over to get those yields.

If you want, you can try it out:

def get_items():              
   for inner_dict in obj["outer_list"]:
       for item in list(inner_dict.values())[0]:
           yield(item)
list(get_items())

The loop could also have been written as

for inner_dict in obj["outer_list"]:
    for inner_list in list(inner_dict.values()):
        for item in inner_list:
            yield(item)

which would have resulted in the list comprehension

[item for inner_dict in obj["outer_list"] for inner_list in inner_dict.values() for item in inner_list]

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.