380

I have this nested list:

l = [['40', '20', '10', '30'], ['20', '20', '20', '20', '20', '30', '20'], ['30', '20', '30', '50', '10', '30', '20', '20', '20'], ['100', '100'], ['100', '100', '100', '100', '100'], ['100', '100', '100', '100']]

I want to convert each element in l to float. I have this code:

newList = []
for x in l:
    for y in x:
        newList.append(float(y))

How can I solve the problem with a nested list comprehension instead?


See also: How can I get a flat result from a list comprehension instead of a nested list?

4
  • 23
    Do you also want to flatten your list? Commented Aug 6, 2013 at 6:05
  • 3
    @GregHewgill: OP didn't reply, but based on the answer they accepted, seems they wanted to keep the nesting as is. Commented Feb 2, 2018 at 20:39
  • 1
    See also: treyhunner.com/2015/12/python-list-comprehensions-now-in-color Commented Feb 18, 2022 at 21:32
  • [float(y) for y in x for x in l] does not work by itself. It is only working because of the existing definition of x left over from previous code. Commented Aug 2, 2022 at 21:43

12 Answers 12

513

Here is how you would do this with a nested list comprehension:

[[float(y) for y in x] for x in l]

This would give you a list of lists, similar to what you started with except with floats instead of strings.

If you want one flat list, then you would use

[float(y) for x in l for y in x]

Note the loop order - for x in l comes first in this one.

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

Comments

406

Here is how to convert nested for loop to nested list comprehension for your example:

newList = []
for x in l:
    for y in x:
        newList.append(float(y))


newList = [
    float(y)
    for x in l
        for y in x
]

Some other examples

students = [
    {"name": "John", "age": 18, "friends": ["Alice", "Bob"]},
    {"name": "Alice", "age": 19, "friends": ["John", "Doe"]},
]

# Normal for loop
friends = []
for student in students:
    for friend_name in student["friends"]:
        friends.append(friend_name)

# List comprehension
friends = [
    friend_name
    for student in students
    for friend_name in student["friends"]
]

For your case, if you want a flat list, it will be something like this.

new_list = [float(y) for x in l for y in x]

Another interesting example with if conditions in the mix:

school_data = [
    {
        "students": [
            {"name": "John", "age": 18, "friends": ["Alice", "Bob"]},
            {"name": "Alice", "age": 19, "friends": ["John", "Bob"]},
        ],
        "teacher": "Mr. Smith",
    },
    {
        "students": [
            {"name": "Sponge", "age": 20, "friends": ["Bob"]},
        ],
        "teacher": "Mr. tom",
    },
]

result = []

for class_dict in school_data:
    for student_dict in class_dict["students"]:
        if student_dict["name"] == "John" and student_dict["age"] == 18:
            for friend_name in student_dict["friends"]:
                if friend_name.startswith("A"):
                    result.append(friend_name)

And here is the listcomp version

result = [
    friend_name
    for class_dict in school_data
        if class_dict["teacher"] == "Mr. Smith"
            for student_dict in class_dict["students"]
                if student_dict["name"] == "John" and student_dict["age"] == 18
                    for friend_name in student_dict["friends"]
                        if friend_name.startswith("A")
]
# result => ['Alice']

2 Comments

Super useful! Makes it clear that loops (top-to-bottom) are ordered left to right in the generator. This not obvious since in (f(x) for x in l) places the second line of the for-loop equivalent on the left.
@user48956 yeah, i don't think it's very intuitive to have a nested list comprehension as a one liner. such usage would be an antipattern imo
64

Not sure what your desired output is, but if you're using list comprehension, the order follows the order of nested loops, which you have backwards. So I got the what I think you want with:

[float(y) for x in l for y in x]

The principle is: use the same order you'd use in writing it out as nested for loops.

3 Comments

This solution is good for times when we don't want to square bracket the iteratool.
This may not be the correct answer because it outputs a non-nested list, but it is what I was looking for, specially the principle.
This is not correct; it should have brackets around [float(y)].
58
>>> l = [['40', '20', '10', '30'], ['20', '20', '20', '20', '20', '30', '20'], ['30', '20', '30', '50', '10', '30', '20', '20', '20'], ['100', '100'], ['100', '100', '100', '100', '100'], ['100', '100', '100', '100']]
>>> new_list = [float(x) for xs in l for x in xs]
>>> new_list
[40.0, 20.0, 10.0, 30.0, 20.0, 20.0, 20.0, 20.0, 20.0, 30.0, 20.0, 30.0, 20.0, 30.0, 50.0, 10.0, 30.0, 20.0, 20.0, 20.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0]

Comments

13

I wanted to share how the list comprehension actually works, especially for nested list comprehensions:

new_list= [float(x) for x in l]

is actually the same as:

new_list=[]
for x in l:
    new_list.append(float(x))

And now for the nested list comprehension:

[[float(y) for y in x] for x in l]

is the same as:

new_list=[]
for x in l:
    sub_list=[]
    for y in x:
        sub_list.append(float(y))

    new_list.append(sub_list)

print(new_list)

output:

[[40.0, 20.0, 10.0, 30.0], [20.0, 20.0, 20.0, 20.0, 20.0, 30.0, 20.0], [30.0, 20.0, 30.0, 50.0, 10.0, 30.0, 20.0, 20.0, 20.0], [100.0, 100.0], [100.0, 100.0, 100.0, 100.0, 100.0], [100.0, 100.0, 100.0, 100.0]]

Comments

10

I had a similar problem to solve so I came across this question. I did a performance comparison of Andrew Clark's and narayan's answer which I would like to share.

The primary difference between two answers is how they iterate over inner lists. One of them uses builtin map, while other is using list comprehension. Map function has slight performance advantage to its equivalent list comprehension if it doesn't require the use lambdas. So in context of this question map should perform slightly better than list comprehension.

Lets do a performance benchmark to see if it is actually true. I used python version 3.5.0 to perform all these tests. In first set of tests I would like to keep elements per list to be 10 and vary number of lists from 10-100,000

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,10))]*10]"
>>> 100000 loops, best of 3: 15.2 usec per loop   
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,10))]*10]"
>>> 10000 loops, best of 3: 19.6 usec per loop 

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,10))]*100]"
>>> 100000 loops, best of 3: 15.2 usec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,10))]*100]"
>>> 10000 loops, best of 3: 19.6 usec per loop 

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,10))]*1000]"
>>> 1000 loops, best of 3: 1.43 msec per loop   
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,10))]*1000]"
>>> 100 loops, best of 3: 1.91 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,10))]*10000]"
>>> 100 loops, best of 3: 13.6 msec per loop   
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,10))]*10000]"
>>> 10 loops, best of 3: 19.1 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,10))]*100000]"
>>> 10 loops, best of 3: 164 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,10))]*100000]"
>>> 10 loops, best of 3: 216 msec per loop

enter image description here

In the next set of tests I would like to raise number of elements per lists to 100.

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,100))]*10]"
>>> 10000 loops, best of 3: 110 usec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,100))]*10]"
>>> 10000 loops, best of 3: 151 usec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,100))]*100]"
>>> 1000 loops, best of 3: 1.11 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,100))]*100]"
>>> 1000 loops, best of 3: 1.5 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,100))]*1000]"
>>> 100 loops, best of 3: 11.2 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,100))]*1000]"
>>> 100 loops, best of 3: 16.7 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,100))]*10000]"
>>> 10 loops, best of 3: 134 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,100))]*10000]"
>>> 10 loops, best of 3: 171 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,100))]*100000]"
>>> 10 loops, best of 3: 1.32 sec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,100))]*100000]"
>>> 10 loops, best of 3: 1.7 sec per loop

enter image description here

Lets take a brave step and modify the number of elements in lists to be 1000

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,1000))]*10]"
>>> 1000 loops, best of 3: 800 usec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,1000))]*10]"
>>> 1000 loops, best of 3: 1.16 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,1000))]*100]"
>>> 100 loops, best of 3: 8.26 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,1000))]*100]"
>>> 100 loops, best of 3: 11.7 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,1000))]*1000]"
>>> 10 loops, best of 3: 83.8 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,1000))]*1000]"
>>> 10 loops, best of 3: 118 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,1000))]*10000]"
>>> 10 loops, best of 3: 868 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,1000))]*10000]"
>>> 10 loops, best of 3: 1.23 sec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,1000))]*100000]"
>>> 10 loops, best of 3: 9.2 sec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,1000))]*100000]"
>>> 10 loops, best of 3: 12.7 sec per loop

enter image description here

From these test we can conclude that map has a performance benefit over list comprehension in this case. This is also applicable if you are trying to cast to either int or str. For small number of lists with less elements per list, the difference is negligible. For larger lists with more elements per list one might like to use map instead of list comprehension, but it totally depends on application needs.

However I personally find list comprehension to be more readable and idiomatic than map. It is a de-facto standard in python. Usually people are more proficient and comfortable(specially beginner) in using list comprehension than map.

Comments

4

If you don't like nested list comprehensions, you can make use of the map function as well,

>>> from pprint import pprint

>>> l = l = [['40', '20', '10', '30'], ['20', '20', '20', '20', '20', '30', '20'], ['30', '20', '30', '50', '10', '30', '20', '20', '20'], ['100', '100'], ['100', '100', '100', '100', '100'], ['100', '100', '100', '100']] 

>>> pprint(l)
[['40', '20', '10', '30'],
['20', '20', '20', '20', '20', '30', '20'],
['30', '20', '30', '50', '10', '30', '20', '20', '20'],
['100', '100'],
['100', '100', '100', '100', '100'],
['100', '100', '100', '100']]

>>> float_l = [map(float, nested_list) for nested_list in l]

>>> pprint(float_l)
[[40.0, 20.0, 10.0, 30.0],
[20.0, 20.0, 20.0, 20.0, 20.0, 30.0, 20.0],
[30.0, 20.0, 30.0, 50.0, 10.0, 30.0, 20.0, 20.0, 20.0],
[100.0, 100.0],
[100.0, 100.0, 100.0, 100.0, 100.0],
[100.0, 100.0, 100.0, 100.0]]

2 Comments

Your code generates map objects instead of lists: >>> float_l = [map(float, nested_list) for nested_list in l] [[<map at 0x47be9b0>], [<map at 0x47be2e8>], [<map at 0x47be4a8>], [<map at 0x47beeb8>], [<map at 0x484b048>], [<map at 0x484b0b8>]] but adding an additional call to list it works as expected: >>> float_l = [list(map(float, nested_list)) for nested_list in l]
@pixelperfect that is due to the (misinformed ..) change in python3 to return generators out of comprehensions.
4

This Problem can be solved without using for loop.Single line code will be sufficient for this. Using Nested Map with lambda function will also works here.

l = [['40', '20', '10', '30'], ['20', '20', '20', '20', '20', '30', '20'], ['30', '20', '30', '50', '10', '30', '20', '20', '20'], ['100', '100'], ['100', '100', '100', '100', '100'], ['100', '100', '100', '100']]

map(lambda x:map(lambda y:float(y),x),l)

And Output List would be as follows:

[[40.0, 20.0, 10.0, 30.0], [20.0, 20.0, 20.0, 20.0, 20.0, 30.0, 20.0], [30.0, 20.0, 30.0, 50.0, 10.0, 30.0, 20.0, 20.0, 20.0], [100.0, 100.0], [100.0, 100.0, 100.0, 100.0, 100.0], [100.0, 100.0, 100.0, 100.0]]

2 Comments

Do lambdas has any performance benefits over say @Andrew Clark or Harry Binswanger's solutions (the more vanilla list comprehension)? As lambdas seem harder to read.
In nearly any other general programming language we would use chained map - along the lines of what you show. But look how ugly it is in python - especially given the output above is not sufficient: it is a generator not a list. Need to add even more boilerplate list(list( .. ) ) to complete the picture. Try out fluentpy and similar libraries to escape this trap to some extent.
0

The best way to do this in my opinion is to use python's itertools package.

>>>import itertools
>>>l1 = [1,2,3]
>>>l2 = [10,20,30]
>>>[l*2 for l in itertools.chain(*[l1,l2])]
[2, 4, 6, 20, 40, 60]

Comments

0
    deck = [] 
    for rank in ranks:
        for suit in suits:
            deck.append(('%s%s')%(rank, suit))

This can be achieved using list comprehension:

[deck.append((rank,suit)) for suit in suits for rank in ranks ]

4 Comments

This does not appear to address the question on top at all. Please note that everything posted as an answer must be an attempt to answer the question it is posted to.
While this code snippet may solve the question, including an explanation really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. Please also try not to crowd your code with explanatory comments, this reduces the readability of both the code and the explanations!
Nested for loop using list comprehension,
Ok, so apparently, this is an attempt to answer the question. However, this appears to be about an entirely different scenario than in OP, you don't even deal with nested lists as input, and even if you change that your suggestion is pretty much what OP already tried. Also, I don't see how an example about cards helps when the question is about converting strings to float.
0
from py_linq import Enumerable

l = [['40', '20', '10', '30'], ['20', '20', '20', '20', '20', '30', '20'], ['30', '20', '30', '50', '10', '30', '20', '20', '20'], ['100', '100'], ['100', '100', '100', '100', '100'], ['100', '100', '100', '100']]

# non-flattened
Enumerable(l).select(lambda ls: Enumerable(ls).select(lambda x: float(x)))

# flattened
Enumerable(l).select_many(lambda ls: Enumerable(ls).select(lambda x: float(x)))

Comments

0

You can use the sum function if you set the start argument to the empty list:

newList = [float(x) for x in sum(l, start=[])]

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.