Obtendo índices de valores verdadeiros em uma lista booleana


87

Eu tenho um trecho do meu código onde devo criar um painel de controle. Quero retornar uma lista de todos os interruptores que estão ativados. Aqui, "on" será igual Truee "off" será igual False. Agora, quero apenas retornar uma lista de todos os Truevalores e suas posições. Isso é tudo que tenho, mas ele apenas retorna a posição da primeira ocorrência de True(esta é apenas uma parte do meu código):

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]

Isso retorna apenas "4"

Respostas:


115

Use enumerate, list.indexretorna o índice da primeira correspondência encontrada.

>>> 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]

Para listas grandes, é melhor usar 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

Ahh entendo, vi algumas perguntas semelhantes me dizendo para usar enumerar, mas acho que estava usando errado. Eu estava definindo a lista igual a x, então fazendo, enumerate(x)mas acho que tudo que eu estava fazendo era enumerar 4? É isso que estava acontecendo? Obrigado pela ajuda
Charles Smith

Além disso, o que está acontecendo quando você faz i for i, xa compreensão da lista? Só estou acostumado a ver i for ipor exemplo, ou um formato semelhante, qual é a função de x? Obrigado
Charles Smith

1
@Amon enumerateretorna um tuplas (ind, valor) durante o loop, agora podemos atribuir os itens da tupla a duas variáveis usando: i, x = (ind, value). Isso é exatamente o que está acontecendo nesse loop.
Ashwini Chaudhary

Oh, eu vejo o que está acontecendo agora. Muito obrigado pela sua ajuda!
Charles Smith

Para qualquer pessoa que use Python3, na itertools.compresssolução, altere o xrangepararange . ( xrangefoi renomeado para rangeem Python 3.)
MehmedB

64

Se você tiver numpy disponível:

>>> 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
Observe que isso retorna uma tupla que requer np.where(states)[0]o uso real dos resultados
Rufus

17

TL; DR : use np.where, pois é a opção mais rápida. Suas opções são np.where, itertools.compresselist comprehension .

Veja a comparação detalhada abaixo, onde pode ser visto que np.wheresupera ambos itertools.compresse tambémlist 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
  • Método 1: usando 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)
  • Método 2: usando itertools.compress
>>> %timeit list(compress(range(len(t)), t))
210 µs ± 704 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)
  • Método 3 (o método mais rápido): usando numpy.where
>>> %timeit np.where(t)
179 µs ± 593 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

2

Você pode usar o filtro para isso:

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

O rangehere enumera os elementos da sua lista e como queremos apenas aqueles onde self.statesestá True, estamos aplicando um filtro com base nesta condição.

Para Python> 3.0:

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


1

Use a forma de compreensão do dicionário,

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

Entrada:

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

Resultado:

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

3
É uma compreensão de dicionário, não compreensão de lista.
Ashwini Chaudhary

1

Usando a multiplicação por elemento e um conjunto:

>>> 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})

Resultado: {4, 5, 7}


1

Basta fazer isso:

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

Obrigado por sua contribuição e bem-vindo ao StackOverflow. No entanto, leia a Ajuda de edição para melhorar sua formatação e também adicione alguma explicação ao seu código. Obrigado!
Será em
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.