2016-09-06 113 views
-1

我試圖創建一個數組的函數AND語句。數組將進入,如果值爲0,它將被放在列表的後面。我的功能工作的大部分時間,但唯一的問題是假的布爾值不斷得到解釋爲0。我創建了一個AND語句來區分0和假的,但它不工作了,我想不通爲什麼。你能否在列表理解中使用AND語句?包括Python列表理解

def move_zeros(array): 
    [array.insert(len(array), array.pop(array.index(x))) for x in array if x == 0 and x is not False] 
    return array 

我已經添加了兩個例子。一個作品。另一個不是爲了我想要完成的。

輸入:[1, 「A」,2,0,3中, 「b」]輸出:[1, 「A」,2,3中, 「b」,0]這工作

輸入: [1,FALSE,2,0,3中, 「b」]輸出:[1,2,3, 「b」 的,FALSE,0]此不起作用,因爲假被移動到列表中時的端我想要通過它。

+0

您能詳細說明一下您的函數在做什麼嗎?順便說一句,你正在創建一個'None'的數組,因爲insert不會返回一個值。 'array.insert(len(array),...)'與'array.append(...)'相同。 – ozgur

+3

你應該學會使用列表解析。這不是他們如何使用。快速經驗法則:如果您的列表理解有副作用,那麼您做錯了。 – spectras

+0

添加一個'array'(列表,我假設)給你的問題。你想要什麼結果。你應該「返回」列表理解,而不是在理解中被修改的列表。 – hpaulj

回答

1

環路替代列表理解。它仍然修改列表。正如其他人指出x is 0簡化的區別0False之間:

In [106]: al=[0, 1, 2, False, True, 3,0,10] 
In [107]: for i,x in enumerate(al): 
    ...:  if x is 0: 
    ...:   value = al.pop(i) 
    ...:   al.append(value) 
    ...:   
In [108]: al 
Out[108]: [1, 2, False, True, 3, 10, 0, 0] 

副作用就是這樣,一環比一的理解更好。理解應該用在:

return [.... for x in al if ...] 

有意義。你也可以在理解中使用枚舉:

return [fun(x, i) for i, x in enumerate(al) if x...] 

在明確的列表理解中,列表只會出現一次;測試和返回值將僅取決於迭代變量,而不取決於原始列表。

===================

要注意的是0False常常被當作是相同的。對於那些希望把數字作爲False0,並且True爲1以及期待布爾將把0False功能的示例操作。在列表理解與and

In [117]: [x+1 for x in al] 
Out[117]: [1, 2, 3, 1, 2, 4, 1, 11] 
In [118]: al=[0, 1, 2, False, True, 3,0,10] 
In [119]: sum(al) 
Out[119]: 17 

=================

實施例:

In [137]: [x for x in al if x==0] 
Out[137]: [0, False, 0] 
In [138]: [x for x in al if x==0 and x is not False] 
Out[138]: [0, 0] 
In [140]: [x for x in al if not (x==0 and x is not False)] 
Out[140]: [1, 2, False, True, 3, 10] 

======== ====

另一種可能的測試 - 的STR表示的:

In [143]: [x for x in al if str(x)!='0'] 
Out[143]: [1, 2, False, True, 3, 10] 

================

您的問題不在測試中,而是在al.index(x);它匹配0False,並刪除第一個,而不管哪個x正在通過您的測試。

版本與al.index(x)

In [396]: al=[1,False,2, 0,3,"b"] 
In [397]: for x in al: 
    ...:  if x ==0 and x is not False: 
    ...:   al.append(al.pop(al.index(x))) 
    ...:   
In [398]: al 
Out[398]: [1, 2, 0, 3, 'b', False] 

版本並具有枚舉i

In [399]: al=[1,False,2, 0,3,"b"] 
In [400]: for i,x in enumerate(al): 
    ...:  if x ==0 and x is not False: 
    ...:   al.append(al.pop(i)) 
    ...:   
In [401]: al 
Out[401]: [1, False, 2, 3, 'b', 0] 

或者在你的函數:

def move_zeros(array): 
    [array.insert(len(array), array.pop(i)) for i,x in enumerate(array) if (x == 0 and x is not False)] 
    return array 

In [403]: al=[1,False,2, 0,3,"b"] 
In [404]: move_zeros(al) 
Out[404]: [1, False, 2, 3, 'b', 0] 

隔離測試index

In [405]: al=[1,False,2, 0,3,"b"] 
In [406]: al.index(0) 
Out[406]: 1 
In [407]: al.index(False) 
Out[407]: 1 
+0

'x是0'是依賴於實現的;不能保證「x是0」只會因爲「x == 0」而成立。 – chepner

+0

是的,在'cpython'(主要的)中,低於256的整數是唯一的,而'is'是有效的。在'pypy'中可能不是這種情況(我記得一個圍繞這個區別的bug /問題)。 – hpaulj

+0

有人可能會爭辯說,一個包含'0'和'False'的列表,並期望他們以不同的方式處理,正在尋求某種麻煩。 – hpaulj

0

在過濾列表時嘗試在0False之間進行語義區分可能是一個糟糕的主意,但是如果您有充足的理由這樣做,有幾種方法可能適用於您的情況。

這在CPython的工作

一個有點hackish的方法是使用is而非==

def move_zeros(array): 
    zeros = 0 
    new_array = [] 
    for x in array: 
     if not x is 0: 
      new_array.append(x) 
     else: 
      zeros += 1 
    return new_array + [0]*zeros 

由於@chepner指出,這是實現相關。這在Python 3工作更加可靠的方法是使用isinstance()

def move_zeros(array): 
    zeros = 0 
    new_array = [] 
    for x in array: 
     if x != 0 or isinstance(x,bool): 
      new_array.append(x) 
     else: 
      zeros += 1 
    return new_array + [0]*zeros 

使用這兩種定義:

>>> move_zeros([1, False, 2, 0, 3, "b"]) 
[1, False, 2, 3, 'b', 0] 
+0

這是依賴於實現的。 – chepner