在Python列表理解中包含AND语句

时间:2016-09-06 22:27:51

标签: python arrays list-comprehension

我正在尝试为数组创建一个函数。数组将进入,如果值为0,它将被放入列表的后面。我的函数大部分时间都在工作,但唯一的问题是布尔值False一直被解释为0.我创建了一个AND语句来区分0和False,但它不起作用,我无法弄清楚为什么。你能不能在列表理解中使用AND语句吗?

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]这不起作用,因为False正被移动到当我想要传递它时,列表的末尾。

2 个答案:

答案 0 :(得分: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通常被视为相同。例如,期望数字将False视为0True视为1的操作。期望布尔值的函数会将0视为False

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

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

列表推导中and的示例:

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

答案 1 :(得分:0)

在过滤列表时尝试在Falseis之间进行语义区分可能是一个坏主意,但是如果你有充分的理由这样做有几种方法可以可能适合你的情况。

在CPython中使用的有点hackish方法是使用==而不是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

isinstance()

正如@chepner所指出的,这是依赖于实现的。在Python 3中使用的更强大的方法是使用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]

使用任一定义:

#include <stdio.h>
#include <stdlib.h>
// TODO: you should use bool instead
int is_all_space(const char *s)
{
  char *tmp;
  tmp = (char *) s;
  // you might check for '\n' instead in your case
  // or even '\r'
  while (*tmp != '\0') {
    // TODO: this check will fail if the input has zero length
    if (*tmp != ' ') {
      return 0;
    }
    tmp++;
  }
  return 1;
}
// don't forget to put the argument in quotes if it contains spaces
int main(int argc, char **argv)
{
  if (argc < 2) {
    fprintf(stderr, "Usage: %s somestring\n", argv[0]);
    exit(EXIT_FAILURE);
  }

  if (is_all_space(argv[1])) {
    puts("Input is all-space and nothing else");
  } else {
    puts("Input it not all-space");
  }
  exit(EXIT_SUCCESS);
}