Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this list comprehension pythonic enough? [duplicate]

Let's say I want to create a list of ints using Python that consists of the cubes of the numbers 1 through 10 only if the cube is evenly divisible by four.

I wrote this working line:

cube4 = [x ** 3 for x in range(1, 11) if (x ** 3) % 4 == 0]

My beef with this line of code is that it's computing the cube of x twice. Is there more pythonic way to write this line? Or is this as good as it'll get in a list comprehension?


Edit - My question is intended to be focused how to avoid extraneous calculation using the features and nuances of Python while still keeping code concise and readable. Though this solution could have probably been reached looking at other questions, I wanted to be sure that I knew the best answer to this question, not just a solution that works.

like image 574
Taylor Lopez Avatar asked May 28 '15 20:05

Taylor Lopez


People also ask

Does list comprehension make a copy?

5. Using list comprehension. The method of list comprehension can be used to copy all the elements individually from one list to another. This takes around 0.217 seconds to complete.

How much faster is list comprehension than for loop?

>> 8.20 seconds As we can see, the for loop is slower than the list comprehension (9.9 seconds vs. 8.2 seconds). List comprehensions are faster than for loops to create lists. But, this is because we are creating a list by appending new elements to it at each iteration.

How much faster are list comprehensions?

It's a simple operation, it's just creating a list of the squares of numbers from 1 to 50000. From the timed cells below, you can see that the list comprehension runs almost twice as fast as the for loop for this calculation. This is one of the primary benefits of using list comprehension.


3 Answers

You can use a generator expression:

cubed = (x ** 3 for x in range(1, 11))
cube4 = [c for c in cubed if c % 4 == 0]

This still iterates over range() only once, but now the x ** 3 expression is calculated just the once as the generator expression is iterated over. You can combine it into one line:

cube4 = [c for c in (x ** 3 for x in range(1, 11)) if c % 4 == 0]

but keeping the generator expression on a separate line may aid in comprehension (no pun intended).

Demo:

>>> [c for c in (x ** 3 for x in range(1, 11)) if c % 4 == 0]
[8, 64, 216, 512, 1000]

Of course, mathematically speaking, for your simple example you could just use [x ** 3 for x in range(2, 11, 2)], but I suspect that wasn't quite the aim of your question. :-)

like image 51
Martijn Pieters Avatar answered Oct 26 '22 23:10

Martijn Pieters


A number's cube is divisible by 4 if and only if the number is even. This is easy to see if you expand each number into its prime factors. Therefore:

cube4 = [x ** 3 for x in range(1, 11) if x % 2 == 0]
like image 39
317070 Avatar answered Oct 27 '22 00:10

317070


I love one-liners, but it's worth noting that there's another Pythonic way to produce the desired list.

cube4 = []
for x in range(1, 11):
    y = x ** 3
    if not y%4:
        cube4.append(y)
like image 44
TigerhawkT3 Avatar answered Oct 26 '22 23:10

TigerhawkT3