2

我经常发现自己有一个对象列表和相关参数列表:param1、param2、param3 等。我想获得具有满足某些条件的参数的对象子集。伪代码将是:

subset = object if param1>10 and 5<param2-param3<6 and param4==1

我知道如何使用列表推导来做到这一点,但它变得非常丑陋,并且很难被其他人阅读。有替代品吗?例如,要两个两个添加列表的元素,很痛苦:

list1=[1,2,3,4]
list2=[10,10,10,10]

[item[0]+item[1] for item in zip(list1,list2)]
>>> [11, 12, 13, 14]

使用 NumPy 数组而不是列表推导式看起来更清晰:

import numpy
list1=numpy.array([1,2,3,4])
list2=numpy.array([10,10,10,10])

list1 + list2
>>> array([11, 12, 13, 14])

当您开始对两个以上的列表进行一些重要的操作时,清晰度的增益会更大。

回到我最初在对象列表中只选择一些行的问题:

subset = [item[0] for item in zip(object,param1,param2,param3,param4) if item[1]>10 and item[2]-item[3]>5 and item[2]-item[3]<6 and item[4]==1]

或者:

subset = [obj for obj,p1,p2,p3,p4 in zip(object,param1,param2,param3,param4) if p1>10 and p2-p3>5 and p2-p3<6 and p4==1]

执行我想要的,但我觉得不是很优雅。更不用说非 pythoneers 很快就开始告诉你“SuperMongo 让它变得更容易”或“你想让我为此放弃 IDL!?”。

您是否知道为该特定任务提供更好语法的替代解决方案?NumPy 数组能否再次帮助简化语法?

4

4 回答 4

2

如果您正确缩进,我认为您的第二个示例可以变得非常可读:

[obj for obj, p1, p2, p3, p4 in zip(object, param1, param2, param3, param4) 
 if p1 > 10 
 and p2 - p3 > 5
 and p2 - p3 < 6
 and p4 == 1]
于 2013-02-27T14:08:59.640 回答
0

您可以使用filter或只使用 for 循环。

于 2013-02-27T14:08:05.117 回答
0

Numpy 数组版本:

subset = objects[(param1>10) & (param2-param3>5) & (param2-param3<6) & (param4==1)]

但是 [] 中的每个操作都会创建一个临时数组,如果数组的大小很大,可能需要一些优化。

于 2013-02-27T14:23:17.317 回答
0

您可以使用map/imapcompress.

from itertools import imap, compress

compress(obj_list, imap(lambda p1, p2, p3, p4: p1 > 10 and 5 < p2 - p3 < 6 and p4 == 1, param1_list, param2_list, param3_list, param4_list))

您还可以将其封装到一个函数中,以提供更简洁的接口。

mask_filter(filter_function, data, masks):

    return compress(data, imap(filter_function, masks))

mask_validator = lambda *params: params[0] > 10 and 5 < params[1] - params[2] < 6 and params[3] == 1
parameter_lists = (param1_list, param2_list, param3_list, param4_list)
mask_filter(mask_validator, obj_list, *parameter_lists)
于 2013-02-27T14:27:08.267 回答