15

I have the following code which I use to map a nested list in Python to produce a list with the same structure.

>>> nested_list = [['Hello', 'World'], ['Goodbye', 'World']]
>>> [map(str.upper, x) for x in nested_list]
[['HELLO', 'WORLD'], ['GOODBYE', 'WORLD']]

Can this be done with list comprehension alone (without using the map function)?

0

5 Answers 5

16

For nested lists you can use nested list comprehensions:

nested_list = [[s.upper() for s in xs] for xs in nested_list]

Personally I find map to be cleaner in this situation, even though I almost always prefer list comprehensions. So it's really your call, since either will work.

Sign up to request clarification or add additional context in comments.

1 Comment

in py3k map requires a list to be applied to it.
6

Remember the Zen of Python:

There is generally more than one -- and probably several -- obvious ways to do it.**

** Note: Edited for accuracy.

Anyway, I prefer map.

from functools import partial
nested_list = map( partial(map, str.upper), nested_list )

1 Comment

You mean : "There should be one– and preferably only one –obvious way to do it"? :)
4

Map is certainly a much cleaner way of doing what you want. You can nest the list comprehensions though, maybe that's what you're after?

[[ix.upper() for ix in x] for x in nested_list]

1 Comment

Yes, it may be cleaner using map but I would like to use a generator.
2

Other posters have given the answer, but whenever I'm having trouble wrapping my head around a functional construct, I swallow my pride and spell it out longhand with explicitly non-optimal methods and/or objects. You said you wanted to end up with a generator, so:

for xs in n_l:
    def doUpper(l):
        for x in l:
            yield x.upper()
    yield doUpper(xs)

for xs in n_l:
    yield (x.upper() for x in xs)

((x.upper() for x in xs) for xs in n_l)

Sometimes it's cleaner to keep one of the longhand versions. For me, map and reduce sometimes make it more obvious, but Python idioms might be more obvious for others.

1 Comment

This is a really good approach. It's also good to add unit tests if you're still not clear on how something might work. TDD is a great way to step through logic. While we are on the topic on the Zen of python "Readability counts."
2

Here is solution for nested list that has arbitrary depth:

def map_nlist(nlist=nlist,fun=lambda x: x*2):
    new_list=[]
    for i in range(len(nlist)):
        if isinstance(nlist[i],list):
            new_list += [map_nlist(nlist[i],fun)]
        else:
            new_list += [fun(nlist[i])]
    return new_list

you want to upper case all you list element, just type

In [26]: nested_list = [['Hello', 'World'], ['Goodbye', [['World']]]]
In [27]: map_nlist(nested_list,fun=str.upper)
Out[27]: [['HELLO', 'WORLD'], ['GOODBYE', [['WORLD']]]]

And more important, this recursive function can do more than this!

I am new to python, feel free to discuss!

4 Comments

Use append instead of +=, to avoid recreating a new list for each item.
@IoannisFilippidis Filippidis Hey thanks for reply, but can you give me more detail about the issue with +=? I don't quite understand the difference... (long time no use python ..)
Let a = list(). With a.append(0) the same list instance is extended with one more element. In contrast, a += [0] creates one new list [0] that is then dismissed from memory. Correction to my earlier comment: I thought that __iadd__ worked like __add__, but using id revealed that it doesn't. More details can be found here.
It's really smart!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.