Подтвердить что ты не робот

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_asel, property_bsel,... которые содержат только значения, указанные либо в записях True, либо в индексах?

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

Ответ 1

Вы можете просто использовать понимание списка:

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 предварительно вычисляются, а не генерируются "на лету".


Изменить. Первая опция эквивалентна itertools.compress, доступной с Python 2.7/3.1. См. @Gary Kerr.

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

Ответ 2

Я вижу 2 варианта.

  • Использование 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]
    
  • Используя понимание списка и запишите его:

    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]
    

Ответ 3

Используйте встроенную функцию 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

Ответ 4

Предполагая, что у вас есть только список элементов и список истинных/необходимых индексов, это должно быть самым быстрым:

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

Это означает, что выбор свойства будет выполнять столько раундов, сколько есть истинных/требуемых индексов. Если у вас есть много списков свойств, которые следуют правилам одного списка тегов (true/false), вы можете создать список индексов, используя те же принципы понимания списка:

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

Это повторяется через каждый элемент в good_objects (при сохранении его индекса с перечислением) и возвращает только индексы, в которых элемент имеет значение true.


Для тех, кто не получает понимание списка, вот английская проза с кодом, выделенным жирным шрифтом:

укажите индекс для каждой группы индекса , элемент, который существует в перечисление хорошие объекты, , если (где) элемент имеет значение True

Ответ 5

Языки Matlab и Scilab предлагают более простой и более элегантный синтаксис, чем Python, для вопроса, который вы задаете, поэтому я думаю, что лучше всего вы можете имитировать Matlab/Scilab, используя пакет Numpy в Python. Делая это, решение вашей проблемы очень красноречиво и элегантно:

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", что перегрузит ваш script (эта проблема не существует с Matlab/Scilab), Обратите внимание, что это решение ограничено массивами чисел, что имеет место в вашем примере.