2016-09-06 114 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