Получение индексов истинных значений в логическом списке


87

У меня есть фрагмент кода, в котором я должен создать коммутатор. Я хочу вернуть список всех включенных переключателей. Здесь «включено» будет равно, Trueа «выключено» равно False. Итак, теперь я просто хочу вернуть список всех Trueзначений и их положения. Это все, что у меня есть, но он возвращает только позицию первого появления True(это всего лишь часть моего кода):

self.states = [False, False, False, False, True, True, False, True, False, False, False, False, False, False, False, False]

def which_switch(self):
    x = [self.states.index(i) for i in self.states if i == True]

Это возвращает только "4"

Ответы:


115

Использование enumerate, list.indexвозвращает индекс первого найденного совпадения.

>>> t = [False, False, False, False, True, True, False, True, False, False, False, False, False, False, False, False]
>>> [i for i, x in enumerate(t) if x]
[4, 5, 7]

Для огромных списков лучше использовать itertools.compress:

>>> from itertools import compress
>>> list(compress(xrange(len(t)), t))
[4, 5, 7]
>>> t = t*1000
>>> %timeit [i for i, x in enumerate(t) if x]
100 loops, best of 3: 2.55 ms per loop
>>> %timeit list(compress(xrange(len(t)), t))
1000 loops, best of 3: 696 µs per loop

Ах, я вижу, я видел похожие вопросы, говорящие мне использовать enumerate, но я думаю, что использовал его неправильно. Я устанавливал список равным x, затем делал, enumerate(x)но я думаю, все, что я делал, это перечислял 4? Это то, что происходило? Спасибо за помощь
Чарльз Смит

И что происходит, когда вы делаете i for i, xв понимании списка? Я только привык видеть i for iнапример или подобный формат, в чем функция x? Спасибо
Чарльз Смит

1
@Amon enumerateвозвращает набор кортежей (IND, значение) в течение цикла, теперь мы можем назначить пункты кортежа двух переменных с помощью: i, x = (ind, value). Именно это и происходит в этом цикле.
Ашвини Чаудхари

О, я вижу, что сейчас происходит. Большое спасибо за вашу помощь!
Чарльз Смит

Для тех, кто использует Python3, в itertools.compressрешении измените значение xrangeна range. ( xrangeбыл переименован rangeв Python 3.)
MehmedB

64

Если у вас есть numpy:

>>> import numpy as np
>>> states = [False, False, False, False, True, True, False, True, False, False, False, False, False, False, False, False]
>>> np.where(states)[0]
array([4, 5, 7])

8
Обратите внимание, что это возвращает кортеж, который требует np.where(states)[0]фактического использования результатов
Руфус

17

TL; ДР : используйте, np.whereпоскольку это самый быстрый вариант. Ваши варианты np.where, itertools.compressи list comprehension.

Смотрите подробное сравнение ниже, где видно, что он np.whereпревосходит оба itertools.compressи такжеlist comprehension .

>>> from itertools import compress
>>> import numpy as np
>>> t = [False, False, False, False, True, True, False, True, False, False, False, False, False, False, False, False]`
>>> t = 1000*t
  • Метод 1: Использование list comprehension
>>> %timeit [i for i, x in enumerate(t) if x]
457 µs ± 1.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
  • Метод 2: Использование itertools.compress
>>> %timeit list(compress(range(len(t)), t))
210 µs ± 704 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)
  • Метод 3 (самый быстрый): Использование numpy.where
>>> %timeit np.where(t)
179 µs ± 593 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

2

Вы можете использовать для этого фильтр:

filter(lambda x: self.states[x], range(len(self.states)))

rangeЗдесь перебирает элементы списка и так как мы хотим только те , где self.statesестьTrue , мы применяем фильтр , основанный на этом условии.

Для Python> 3.0:

list(filter(lambda x: self.states[x], range(len(self.states))))


1

Используйте способ понимания словаря,

x = {k:v for k,v in enumerate(states) if v == True}

Вход:

states = [False, False, False, False, True, True, False, True, False, False, False, False, False, False, False, False]

Выход:

{4: True, 5: True, 7: True}

3
Это понимание слов, а не понимание списка.
Ашвини Чаудхари

1

Используя поэлементное умножение и набор:

>>> states = [False, False, False, False, True, True, False, True, False, False, False, False, False, False, False, False]
>>> set(multiply(states,range(1,len(states)+1))-1).difference({-1})

Выход: {4, 5, 7}


1

Просто сделайте это:

def which_index(self):
    return [
        i for i in range(len(self.states))
        if self.states[i] == True
    ]

Спасибо за ваш вклад и добро пожаловать в StackOverflow. Однако, пожалуйста, прочтите Справку по редактированию, чтобы улучшить форматирование, а также добавьте некоторые пояснения к своему коду. Благодарность!
Will
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.