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

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

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]
260353 次浏览

你可以使用 列表内涵:

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_indicesproperty_a的长度少,假设 good_indices是预先计算的,而不是动态生成的。


编辑 : 第一个选项相当于自 Python 2.7/3.1以来可用的 itertools.compress

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

我有两个选择。

  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. Using a list comprehension and zip it:

    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]
    

使用内置函数 什么都没有

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

假设您只有条目列表和真/必需索引列表,这应该是最快的:

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

这意味着属性选择只会执行与 true/必需索引相同的轮次。如果你有很多的属性列表,它们遵循单个标签列表的规则(真/假) ,你可以使用相同的列表内涵原则创建一个索引列表:

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

这会遍历 good _ object 中的每个项目(同时记住其带枚举的索引) ,并且只返回项目为 true 的索引。


对于那些没有列表内涵的人,这里有一个英文散文版,代码用粗体突出显示:

列出存在 进去好东西枚举如果(其中) 项目是真实的的每一组 索引,项目

对于你提出的问题,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 不存在这个问题)。请注意,此解决方案仅限于数字数组,您的示例就是这种情况。