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)?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
kjfletch
  • 5,394
  • 3
  • 32
  • 38

5 Answers5

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.

Eli Courtwright
  • 186,300
  • 67
  • 213
  • 256
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 )
Stuart Berg
  • 17,026
  • 12
  • 67
  • 99
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]
KayEss
  • 2,290
  • 15
  • 31
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.

Karl Anderson
  • 1,798
  • 11
  • 18
  • 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." – Peter Suwara Feb 18 '23 at 20:41
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!

Oldyoung
  • 567
  • 4
  • 8
  • Use `append` instead of `+=`, to avoid recreating a new list for each item. – 0 _ Jun 18 '15 at 08:38
  • @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 ..) – Oldyoung Jan 20 '16 at 21:13
  • 1
    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](http://stackoverflow.com/questions/9766387/different-behaviour-for-list-iadd-and-list-add). – 0 _ Jan 24 '16 at 22:21