有条件将列表拆分为多个列表

时间:2019-02-22 22:36:19

标签: python python-3.x list

我有这样的代码,可以根据自己的条件从一个列表中列出4个列表。拆分取决于列表元素的符号。 就像我想获取所有正数的列表,列出第一个元素为正,第二个元素为负的列表,等等...以及所有这样的组合。 当所有列表仅包含2个元素时,使用过滤器轻松创建4个列表即可。

vals=[(0, 0), (0, 1), (0, -1), (1, 0), (1, 1), (1, -1), (-1, 0), (-1, 1), (-1, -1)]
new_f=list(filter(lambda x:x[0]>=0,vals))
new_f=list(filter(lambda x:x[1]>=0,new_f))
print(new_f)
new_f=list(filter(lambda x:x[0]<=0,vals))
new_f=list(filter(lambda x:x[1]>=0,new_f))
print(new_f)
new_f=list(filter(lambda x:x[0]>=0,vals))
new_f=list(filter(lambda x:x[1]<=0,new_f))
print(new_f)
new_f=list(filter(lambda x:x[0]<=0,vals))
new_f=list(filter(lambda x:x[1]<=0,new_f))
print(new_f)

这是我的输出:

[(0, 0), (0, 1), (1, 0), (1, 1)]
[(0, 0), (0, 1), (-1, 0), (-1, 1)]
[(0, 0), (0, -1), (1, 0), (1, -1)]
[(0, 0), (0, -1), (-1, 0), (-1, -1)]

但是,如果我的元素的长度为3或更多,我怎么能不写所有条件呢(对于len = 4,将有2 ** 3种情况和2 ** 4种情况) 例如,这是我对n = 3的输入,以及当我想通过“没有否定”和“第一个负数而不是其他负数”进行过滤时的情况示例。

vals=[(0, 0, 0), (0, 0, 1), (0, 0, -1), (0, 1, 0), (0, 1, 1), (0, 1, -1), (0, -1, 0), (0, -1, 1), (0, -1, -1), (1, 0, 0), (1, 0, 1), (1, 0, -1), (1, 1, 0), (1, 1, 1), (1, 1, -1), (1, -1, 0), (1, -1, 1), (1, -1, -1), (-1, 0, 0), (-1, 0, 1), (-1, 0, -1), (-1, 1, 0), (-1, 1, 1), (-1, 1, -1), (-1, -1, 0), (-1, -1, 1), (-1, -1, -1)]
new_f=list(filter(lambda x:x[0]>=0,vals))
new_f=list(filter(lambda x:x[1]>=0,new_f))
new_f=list(filter(lambda x:x[2]>=0,new_f))
print(new_f)
new_f=list(filter(lambda x:x[0]<=0,vals))
new_f=list(filter(lambda x:x[1]>=0,new_f))
new_f=list(filter(lambda x:x[2]>=0,new_f))
print(new_f)

此处输出:

[(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1), (1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1)]
[(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1), (-1, 0, 0), (-1, 0, 1), (-1, 1, 0), (-1, 1, 1)]

因此,我需要对该过程进行某种程度的自动化,以使其与更长的数组配合使用。

2 个答案:

答案 0 :(得分:2)

列出列表。每个大列表的索引是比较的二进制方向:1True代表正数,0False代表负数。称为mask

遍历所有可能的掩码,从0到2 ^ n-1。对于每个蒙版,将布尔向量转换为系数序列。例如,掩码9是二进制1001,系数序列为[1,-1,-1、1]。将元组乘以面罩;例如

(0, 1, -1, 1) * [1, -1, -1, 1] => [0, -1, 1, 1]

根据候选人列表中的allmask,使用element函数过滤整个向量。

all(bit >= 0 for bit in 
    [element[i] * mask[i] for i in len(element)])

现在,将其包装在循环中,以循环访问掩码值。如果足够持久,则可以使用all和嵌套的理解,在一行代码中创建2 ^ n个过滤列表的整个列表。我建议将其留给深夜黑客,而不是解决问题。

还请注意,itertools.permutations很高兴为您生成掩码。

答案 1 :(得分:1)

您可以在两个过滤器函数中使用itertools.product,输入中元组的大小为repeat,然后zip过滤器函数在每个元组中仅包含单个项如果满足所有过滤条件,则输出元组:

[[t for t in vals if all(f(i) for (f, i) in zip(filters, t))] for filters in product(((0).__le__, (0).__ge__), repeat=len(vals[0]))]

以便您输入示例内容:

vals = [(0, 0, 0), (0, 0, 1), (0, 0, -1), (0, 1, 0), (0, 1, 1), (0, 1, -1), (0, -1, 0), (0, -1, 1), (0, -1, -1), (1, 0, 0), (1, 0, 1), (1, 0, -1), (1, 1, 0), (1, 1, 1), (1, 1, -1), (1, -1, 0), (1, -1, 1), (1, -1, -1), (-1, 0, 0), (-1, 0, 1), (-1, 0, -1), (-1, 1, 0), (-1, 1, 1), (-1, 1, -1), (-1, -1, 0), (-1, -1, 1), (-1, -1, -1)]

这将返回:

[[(0, 0, 0),
  (0, 0, 1),
  (0, 1, 0),
  (0, 1, 1),
  (1, 0, 0),
  (1, 0, 1),
  (1, 1, 0),
  (1, 1, 1)],
 [(0, 0, 0),
  (0, 0, -1),
  (0, 1, 0),
  (0, 1, -1),
  (1, 0, 0),
  (1, 0, -1),
  (1, 1, 0),
  (1, 1, -1)],
 [(0, 0, 0),
  (0, 0, 1),
  (0, -1, 0),
  (0, -1, 1),
  (1, 0, 0),
  (1, 0, 1),
  (1, -1, 0),
  (1, -1, 1)],
 [(0, 0, 0),
  (0, 0, -1),
  (0, -1, 0),
  (0, -1, -1),
  (1, 0, 0),
  (1, 0, -1),
  (1, -1, 0),
  (1, -1, -1)],
 [(0, 0, 0),
  (0, 0, 1),
  (0, 1, 0),
  (0, 1, 1),
  (-1, 0, 0),
  (-1, 0, 1),
  (-1, 1, 0),
  (-1, 1, 1)],
 [(0, 0, 0),
  (0, 0, -1),
  (0, 1, 0),
  (0, 1, -1),
  (-1, 0, 0),
  (-1, 0, -1),
  (-1, 1, 0),
  (-1, 1, -1)],
 [(0, 0, 0),
  (0, 0, 1),
  (0, -1, 0),
  (0, -1, 1),
  (-1, 0, 0),
  (-1, 0, 1),
  (-1, -1, 0),
  (-1, -1, 1)],
 [(0, 0, 0),
  (0, 0, -1),
  (0, -1, 0),
  (0, -1, -1),
  (-1, 0, 0),
  (-1, 0, -1),
  (-1, -1, 0),
  (-1, -1, -1)]]