Python:根据索引集从列表中选择子集

时间:2010-07-05 11:30:34

标签: python list

我有几个列表具有相同数量的条目(每个都指定一个对象属性):

property_a = [545., 656., 5.4, 33.]
property_b = [ 1.2,  1.3, 2.3, 0.3]
...

并列出具有相同长度的标志

good_objects = [True, False, False, True]

(可以很容易地用等效的索引列表代替:

good_indices = [0, 3]

生成新列表property_aselproperty_bsel,...的最简单方法是什么?它只包含由True条目或索引指示的值?

property_asel = [545., 33.]
property_bsel = [ 1.2, 0.3]

5 个答案:

答案 0 :(得分:95)

您可以使用list comprehension

property_asel = [val for is_good, val in zip(good_objects, property_a) if is_good]

property_asel = [property_a[i] for i in good_indices]

后者更快,因为good_indices的长度比property_a的长度短,假设good_indices是预先计算的,而不是即时生成的。


编辑:第一个选项相当于自Python 2.7 / 3.1以来可用的itertools.compress。请参阅@Gary Kerr的回答。

property_asel = list(itertools.compress(good_objects, property_a))

答案 1 :(得分:18)

我看到两个选项。

  1. 使用numpy:

    property_a = numpy.array([545., 656., 5.4, 33.])
    property_b = numpy.array([ 1.2,  1.3, 2.3, 0.3])
    good_objects = [True, False, False, True]
    good_indices = [0, 3]
    property_asel = property_a[good_objects]
    property_bsel = property_b[good_indices]
    
  2. 使用列表理解并压缩它:

    property_a = [545., 656., 5.4, 33.]
    property_b = [ 1.2,  1.3, 2.3, 0.3]
    good_objects = [True, False, False, True]
    good_indices = [0, 3]
    property_asel = [x for x, y in zip(property_a, good_objects) if y]
    property_bsel = [property_b[i] for i in good_indices]
    

答案 2 :(得分:15)

使用内置函数zip

property_asel = [a for (a, truth) in zip(property_a, good_objects) if truth]

修改

只看2.7的新功能。现在itertools模块中有一个与上面代码类似的函数。

http://docs.python.org/library/itertools.html#itertools.compress

itertools.compress('ABCDEF', [1,0,1,0,1,1]) =>
  A, C, E, F

答案 3 :(得分:7)

假设您只有项目列表和真实/必需指数列表,这应该是最快的:

property_asel = [ property_a[index] for index in good_indices ]

这意味着属性选择将只执行与真实/必需索引一样多的轮次。如果您有许多属性列表遵循单个标记(真/假)列表的规则,您可以使用相同的列表推导原则创建索引列表:

good_indices = [ index for index, item in enumerate(good_objects) if item ]

这遍历good_objects中的每个项目(同时用枚举记住它的索引)并仅返回item为true的索引。


对于没有获得列表理解的人,这里是一个英文散文版本,代码用粗体突出显示:

列出索引 枚举 索引的每一组好的对象如果(其中)项为True

答案 4 :(得分:1)

对于您提出的问题,Matlab和Scilab语言提供了比Python更简单,更优雅的语法,因此我认为您可以做的最好的方法是使用Python中的Numpy包来模仿Matlab / Scilab。通过这样做,您的问题的解决方案非常简洁和优雅:

from numpy import *
property_a = array([545., 656., 5.4, 33.])
property_b = array([ 1.2,  1.3, 2.3, 0.3])
good_objects = [True, False, False, True]
good_indices = [0, 3]
property_asel = property_a[good_objects]
property_bsel = property_b[good_indices]

Numpy尝试模仿Matlab / Scilab,但这需要付出代价:你需要使用关键字" array"来声明每个列表,这会使你的脚本超载(这个问题不存在)用Matlab / Scilab)。请注意,此解决方案仅限于数字数组,在您的示例中就是这种情况。