给出像
这样的列表[None, None, 90, 10, None, 34, None, 108]
在不影响其他元素顺序的情况下,将所有None
移动到最后的简单方法是什么?所以,你得到像
[90, 10, 34, 108, None, None, None, None]
一种可能的解决方案是将filter
与None
一起使用,然后在最后添加None
:
In [890]: l2 = list(filter(None, l))
In [891]: l2 += [None] * (len(l) - len(l2))
In [892]: l2
Out[892]: [90, 10, 34, 108, None, None, None, None]
然而,
filter(None, ...)
并不代表"过滤掉None
s&#34 ;;None
是 特殊情况下的身份谓词,所以这也将过滤掉 0,False以及从__bool__
返回False的任何其他内容。
所以,这不是一个好的解决方案。还有什么更好的吗?
答案 0 :(得分:8)
此将保留列表的排序:
>>> l = [None, None, 90, 10, None, 34, None, 108]
>>> sorted(l, key = lambda x: x is None)
[90, 10, 34, 108, None, None, None, None]
因为,引用python docs:
内置的sorted()函数保证稳定。如果排序保证不更改比较相等的元素的相对顺序,则排序是稳定的 - 这有助于在多个过程中进行排序(例如,按部门排序,然后按工资等级排序)。
答案 1 :(得分:5)
我不知道Big O
但是这个:
l2 = [x for x in l if x is not None]
l2 += [None] * l.count(None)
正常工作,
l2.extend([None] * l.count(None))
受到许多蟒蛇的喜爱和
l2 += [None] * (len(l) - len(l2))
是better。
答案 2 :(得分:5)
我建立一个没有Nones的列表并填充它:
l2 = [x for x in l if x is not None]
l2 += [None] * (len(l) - len(l2))
或者,这是一个单行。我认为它在理论上是O(nlogn),但我没有观察到在实践中 - 我认为Timsort的疾驰模式将所涉及的比较减少到接近但不太接近O(n)的比较,并且数据移动成本太低,不足以支配运行时,即使它们是O(nlogn)。在实践中,更大的缺点可能是你必须考虑如何订购布尔值:
sorted(l, key=lambda x: x is None)
答案 3 :(得分:3)
让你夜不能寐的解决方案:
>>> 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]
<强>解释强>
我们使用*example
将数据传递给我们的函数,以便列表的元素成为参数。然后,我们使用(a, *b)
在函数调用中对这些参数进行分段,将第一个参数放在a
中,其余参数放在b
中。递归地,如果a
是None
,那么答案是:
[*some(*b), a]
将a
移至最后。否则,答案是:
[a, *some(*b)]
将a
保留在前面并处理列表的其余部分。
最后,我们有if b else [a]
位,这只是我们递归的基本情况。
<强>烘烤关闭
我们有足够的解决方案,是时候进行烘烤了。 (如果我歪曲了你的解决方案,请告诉我们。)我们将总结10,000个元素列表的10个时间,其中30%的元素是None
。我已经从数据中删除了零,以便每个人都可以玩:
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"))
排序典型最佳运行:(最低最佳)
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
答案 4 :(得分:1)
此解决方案使用itertools.zip_longest
填充None
s的两个序列中较短的一个。第一个序列是原始列表中的非None
项,第二个序列是完整原始序列。 zip_longest
将返回每个序列的项目元组,填充为None,两者中较短的一个。然后我们重新压缩那些元组以获取序列,并取第一个序列,表示根据需要填充尽可能多None
s的过滤序列,与原始序列一样长。
>>> from itertools import zip_longest
>>>
>>> seq = [None, None, 90, 10, None, 34, None, 108]
>>>
>>> non_nones = filter(lambda x: x is not None, seq)
>>>
>>> reordered = next(zip(*zip_longest(non_nones, seq)))
>>>
>>> print(reordered)
(90, 10, 34, 108, None, None, None, None)
答案 5 :(得分:1)
@cdlane的解决方案让我想到了使用reduce
:
>>> seq = [None, None, 90, 10, None, 34, None, 108]
>>>
>>> from functools import reduce
>>> reordered = sum(reduce(lambda a,b: (a[0], a[1]+(b,))
if b is None else (a[0]+(b,), a[1]),
seq, ((), ())), ())
>>> print(reordered)
(90, 10, 34, 108, None, None, None, None)
编辑: 我无法想到所有那些元组添加,这是更好的:
>>>> reordered = sum(reduce(lambda a,b: a[b is None].append(b) or a, seq, ([], [])), [])