2017-08-03 36 views
2

鑑於像將所有`None`到

[None, None, 90, 10, None, 34, None, 108] 

什麼是移動所有None s到年底,而不會干擾其他元素的順序,一個簡單的方法列表的列表(python3)的結束?所以,你會得到類似

[90, 10, 34, 108, None, None, None, None] 

一個可能的解決方案是使用filterNone,然後只在最後追加None S:

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」; None是 特殊的謂詞,所以這也會過濾掉 0,False,以及其他從__bool__返回False的其他內容。

所以,這不是一個好的解決方案。有更好的嗎?

+0

@vaultah 1.「如何在Python2中完成」2. 0s,而不是Nones。對不起,但這不是一個騙局。 –

+1

你應該不僅能夠做「將X移動到開頭」到「將Y移動到最後」的翻譯。另外,請不要在沒有其他人的支持的情況下重新打開你的問題。 – poke

+0

@poke它甚至不是相同的Python版本。 –

回答

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)) 

被許多pythonists喜愛和

l2 += [None] * (len(l) - len(l2)) 

better

+0

我建議將最後一行改爲'l2.extend(無範圍內的x(none_count)')。生成器表達式會更快,內存更少,因爲您不必分配單獨的數組。 – Zizouz212

+0

@ Zizouz212:完成它 – Rahul

+0

'l = [x for x in l如果x不是None] + [x for x in l如果x是None]' – DragonBobZ

5

我想建立一個列表,而不諾內斯和填充它:

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) 
+0

誰低估了這個?它完美的作品。 –

+0

另外,我看到我在填充的正確軌道上。 –

+0

爲什麼這個O(nlogn)?我認爲這只是O(n),而非常pythonic – user2341726

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()函數保證穩定。如果確保不會更改比較相等的元素的相對順序,則排序是穩定的 - 這對於多次排序(例如,按部門排序,然後按薪級)進行排序很有幫助。

+0

Plus1。尼斯。我最初嘗試過,但無法解決它。 – Rahul

+0

_「這應該保留排序」_ _這_will_保留列表元素的順序。從[文檔](https://docs.python.org/3.5/library/functions.html#sorted):「內置的排序()函數保證穩定。」 –

+0

@Rawing謝謝,更新了帖子 – Massimiliano

1

該解決方案使用itertools.zip_longest填充兩個序列中較短的一個爲None s。第一個序列是來自原始列表的非None項目,第二個是完整原始序列。 zip_longest將從每個序列中返回項目的元組,爲兩者中較短的一個填充無。然後,我們重新壓縮這些元組以取回序列,並採用第一個序列,表示根據需要填充的儘可能多的被過濾的序列與原始序列一樣長。

>>> 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) 
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中。遞歸,如果aNone,那麼答案是:

[*some(*b), a] 

其移動a到底。否則,答案是:

[a, *some(*b)] 

它將a保留在前面並處理列表的其餘部分。

最後,我們有if b else [a]位,這只是我們遞歸的基本情況。

烘烤關

我們的已經夠多的解決方案,它的時間爲一個烘烤過。 (讓我知道如果我誤解了你的解決方案。)我們將總結10,000個元素列表的十個時間點,其中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 
+0

你打算在你的神奇獨角獸上飛走嗎?或者你打算解釋它是如何工作的? :p –

+0

這個缺點是把所有的falsy物體和None一樣處理,就像cᴏʟᴅsᴘᴇᴇᴅ的原始'過濾器'一樣。 – user2357112

+0

'不是a'應該是'a是None'以允許錯誤的非無值(如0)。 – PaulMcG

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, ([], [])), []) 
相關問題