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]
Ответы
Ответ 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), Обратите внимание, что это решение ограничено массивами чисел, что имеет место в вашем примере.