Christopher Weckesser
Christopher Weckesser

Reputation: 373

Merging list comprehensions in Python

Is it possible to combine the following python list comprehensions into a single line? I know it's not necessary, I'm just curious.

rows = [row.split() for row in data]
flattened = [float(val) for sublist in rows for val in sublist]

Below is a snippet of the data file,

['  -.2098335E-03  -.2108988E-03  -.2119629E-03  -.2130240E-03  -.2140826E-03', '  -.2151421E-03  -.2161973E-03  -.2172531E-03  -.2183025E-03  -.2193489E-03', '  -.2203825E-03  -.2214097E-03  -.2224521E-03  -.2235475E-03  -.2246843E-03'....]

I'm trying to extract each of the strings and make a single list of numbers. The code above currently does that, I was wanting to see if it could get even more condensed.

Thanks!

Upvotes: 3

Views: 827

Answers (5)

OysterShucker
OysterShucker

Reputation: 5531

Since sublist is your row.split(), simply replace it.

data = ['0.3 0.6 0.9', '0.1 0.4 0.3']

flattened = [float(val) for row in data for val in row.split()]

print(flattened) #[0.3, 0.6, 0.9, 0.1, 0.4, 0.3]

If we expand it, it becomes more clear.

data = ['0.3 0.6 0.9', '0.1 0.4 0.3']

#the generator is identically replacing this part
flattened = list()
for row in data:
    for val in row.split():
        flattened.append(float(val))

All of the answers that suggest the solution below, are trying to wrap the source loop with the content loop.

#               v--contents--v      wrapping       v--source       
[float(val) for sublist in (row.split() for row in data) for val in sublist] 

It should be the other way around.

[float(val) for row in data for val in row.split()]

Upvotes: 2

Anshika Singh
Anshika Singh

Reputation: 1044

Nested List Comprehensions

Nested List Comprehensions are nothing but a list comprehension within another list comprehension which is quite similar to nested for loops.

When we create a new list (of squares) from the elements of the existing list, using list comprehensions, we write:

l1=[1,2,3]
l2=[i**2 for i in l1]
print(l2)

This gives the output:

[1, 4, 9]

We can also nest two or even more for loops in this comprehension.

For example:

l1=[1,2,3]
l2=[4,5,6]
l3=[[i**2,j**2] for i in l1 for j in l2]
print(l3)

The output:

[[1, 16], [1, 25], [1, 36], [4, 16], [4, 25], [4, 36], [9, 16], [9, 25], [9, 36]]

Similarly:

l1=[1,2]
l2=[3,4]
l3=[5,6]
l4=[[i,j,k] for i in l1 for j in l2 for k in l3]
print(l4)

Output:

[[1, 3, 5], [1, 3, 6], [1, 4, 5], [1, 4, 6], [2, 3, 5], [2, 3, 6], [2, 4, 5], [2, 4, 6]]

Similarly your code can be re-written using the help of list comprehensions as:

flattened = [float(val) for sublist in (row.split() for row in data) for val in sublist]

Hope this helped you!

Upvotes: 1

DirtyBit
DirtyBit

Reputation: 16772

If the intention is only to merge into a one-liner, you can use a generator expression (thanks to @OneCricketeer) that would generate item only when in demand and making it memory efficient than the lists:

flattened = [float(val) for sublist in (row.split() for row in data) for val in sublist]

Upvotes: 0

Gustav Rasmussen
Gustav Rasmussen

Reputation: 3961

One liner:

data = ["1 2",
        "3 4",
        "5 6",
        "7 8",
        "9 10"
        ]

rows = [float(val) for row in data for sublist in row.split() for val in sublist]
print(rows)

Returns:

[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 1.0, 0.0]

Upvotes: 0

Luke Storry
Luke Storry

Reputation: 6702

You can just use [float(val) for sublist in (row.split() for row in data) for val in sublist] but it is much more readable (and easier to debug in the future) to keep them out on seperate lines

Upvotes: 1

Related Questions