A solution to keep you up at night:
>>> example = [None, None, 90, 10, None, 34, None, 108]
>>>
>>> def some(a, *b):
... return ([*some(*b), a] if a is None else [a, *some(*b)]) if b else [a]
...
>>> print(some(*example))
[90, 10, 34, 108, None, None, None, None]
Explanation
We pass the the data into our function using *example
so that the elements of the list become arguments. We then segment these arguments at function call using (a, *b)
to place the first argument in a
and the rest in b
. Recursively, if a
is None
then the answer is:
[*some(*b), a]
which moves a
to the end. Otherwise, the answer is:
[a, *some(*b)]
which keeps a
in front and processes the rest of the list.
Finally, we have the if b else [a]
bit which is just the base case of our recursion.
Bake-Off
We've enough solutions that it's time for a bake-off. (Let me know if I've misrepresented your solution.) We'll be summing up ten timings of a 10,000 element list in which 30% of the elements are None
. I've eliminated zeros from the data so that everyone can play:
import sys
import timeit
import random
A = [random.randint(1, 1000) if random.random() > 0.3 else None for _ in range(10000)] # ~30% None
def Rahul_comprehension(A):
B = [x for x in A if x is not None]
B += [None] * A.count(None)
return B
def coldspeed_filter(A):
B = list(filter(None, A))
B += [None] * (len(A) - len(B))
return B
def user2357112_comprehension(A):
B = [x for x in A if x is not None]
B += [None] * (len(A) - len(B))
return B
sys.setrecursionlimit(100000)
def cdlane_recursion(A):
def some(a, *b):
return ([*some(*b), a] if a is None else [a, *some(*b)]) if b else [a]
return some(*A)
from functools import reduce
def PaulMcG_reduce(A):
return sum(reduce(lambda a,b: a[b is None].append(b) or a, A, ([], [])), [])
from itertools import zip_longest
def PaulMcG_zip_longest(A):
non_nones = filter(lambda x: x is not None, A)
return next(zip(*zip_longest(non_nones, A)))
def Massimiliano_sorted(A):
return sorted(A, key=lambda x: x is None)
# sanity check to make sure everyone agrees on the answer
B = Rahul_comprehension(A) # the accepted answer
assert B == coldspeed_filter(A)
assert B == user2357112_comprehension(A)
assert B == cdlane_recursion(A)
assert B == PaulMcG_reduce(A)
assert B == list(PaulMcG_zip_longest(A))
assert B == Massimiliano_sorted(A)
print("Rahul_comprehension:", format(timeit.timeit('B = Rahul_comprehension(A)', number=10, globals=globals()), ".2"))
print("coldspeed_filter:", format(timeit.timeit('B = coldspeed_filter(A)', number=10, globals=globals()), ".2"))
print("user2357112_comprehension:", format(timeit.timeit('B = user2357112_comprehension(A)', number=10, globals=globals()), ".2"))
print("cdlane_recursion:", format(timeit.timeit('B = cdlane_recursion(A)', number=10, globals=globals()), ".2"))
print("PaulMcG_reduce:", format(timeit.timeit('B = PaulMcG_reduce(A)', number=10, globals=globals()), ".2"))
print("PaulMcG_zip_longest:", format(timeit.timeit('B = PaulMcG_zip_longest(A)', number=10, globals=globals()), ".2"))
print("Massimiliano_sorted:", format(timeit.timeit('B = Massimiliano_sorted(A)', number=10, globals=globals()), ".2"))
Sorted Typical Best Runs: (lowest is best)
coldspeed (filter): 0.002
user2357112 (comprehension): 0.0041
Rahul (comprehension): 0.0061
PaulMcG (zip_longest): 0.024
PaulMcG (reduce): 0.025
Massimiliano (sorted): 0.026
cdlane (recursion): 5.8