Complicated list view is slower than straight loop

I saw an interesting solution for programming exercises in leetcode It's not even about the problem / solution itself, so you can read it from the link if you like. The highly voted solution, however, is one liner:

Fragment 1

def fizzBuzz2(n):
    return  ["Fizz" * (not i%3) + "Buzz" * (not i%5) or str(i) for i in range(1, n+1)]

      

Fragment 2

def fizzBuzz(n):
    out = []
    for i in range(1, n+1):
        if i % 3 == 0 and i % 5 == 0:
            out.append("FizzBuzz")
        elif i % 3 == 0:
            out.append("Fizz")
        elif i % 5 == 0:
            out.append("Buzz")
        else:
            out.append(str(i))

    return out

      

However, I expected the list comprehension to beat the general loop, but when I timed it and it didn't. Even doing this, Snippet 2 has more instructions.

What makes Snippet 1 slow?

+3


source to share


4 answers


your snippet

def fizzBuzz2(n):
    return  ["Fizz" * (not i%3) + "Buzz" * (not i%5) or str(i) for i in range(1, n+1)]

      

does a lot of string concatenations (even with empty strings). I have exchanged this with an additional modular operation that preserves the concatenation and is already faster.

def fizzBuzz3(n):
    return  ["FizzBuzz" if not i%15 else "Fizz" if not i%3 else "Buzz" if not i%5 else str(i) for i in range(1, n+1)]

      

and BTW on my machine, both understandings are faster than the "classic" approach, so I get different results than you stated:



your comp: 4.927702903747559
my listcomp: 4.343341112136841
classical: 6.015967845916748

      

So my optimized listcomp wins (and seems to wins on your machine) even though I am not satisfied with the additional module operations caused by listcomp's flow control)

My test protocol runs 10,000 times the operation with n=1000

:

import time
start_time = time.time()
for i in range(10000):
    fizzBuzz2(1000)
print("your comp:",time.time()-start_time)
start_time = time.time()
for i in range(10000):
    fizzBuzz3(1000)
print("my listcomp:",time.time()-start_time)
start_time = time.time()
for i in range(10000):
    fizzBuzz(1000)
print("classical:",time.time()-start_time)

      

note that even with pre-computation of modules in the "classic" approach it drops to 5.375272035598755

seconds (which is good), but still worse than a list because of all the instructions (you also kill the speed of listcomp by calling the save method of modular computation). I am guessing that python is not the proper language to get top speed in this case.

+3


source


Many people have already answered your question, but I want to add that there are even faster solutions. It doesn't seem right to me to check the numbers in retrospect, although you already know where Fizz, Buzz and FizzBuzz will be. Try this instead:

def fizz_buzz(n):
    result = []
    for i in range(1, n + 1, 15):
        result += [str(i), str(i + 1), 'Fizz',
                   str(i + 3), 'Buzz', 'Fizz',
                   str(i + 6), str(i + 7), 'Fizz', 'Buzz',
                   str(i + 10), 'Fizz', str(i + 12), str(i + 13),
                   'FizzBuzz']
    return result[:n - len(result)]

start_time = time()
for i in range(10000):
    fizz_buzz(1000)
print("fizz_buzz:", time() - start_time)

      



Compared to previous answers:

your comp: 3.3942723274230957
my listcomp: 2.586350202560425
classical: 3.879168748855591
fizz_buzz: 1.6374053955078125

      

+2


source


Yes, because in the understanding, all teams are evaluated in each cycle.

Whereas in Snippet 2

the highest 1 if

branch is executed . Thus, reducing the computation and making it a faster alternative.

+1


source


While they were looking into implementations, here's a fun snippet that's faster than a single list comprehension, but not nearly as fast as @seenorths' solution:

from math import ceil


def fizz_buzz(n):
    result = list(range(n))
    result[::3] = ["Fizz"] * ceil(n / 3)
    result[::5] = ["Buzz"] * ceil(n / 5)
    result[::15] = ["FizzBuzz"] * ceil(n / 15)

    return list(map(str, result))

      

+1


source







All Articles