Mendapatkan indeks nilai True dalam daftar boolean

88

Saya memiliki bagian dari kode saya di mana saya seharusnya membuat switchboard. Saya ingin mengembalikan daftar semua sakelar yang aktif. Di sini "on" akan sama Truedan "off" sama False. Jadi sekarang saya hanya ingin mengembalikan daftar semua Truenilai dan posisinya. Ini semua yang saya miliki tetapi hanya mengembalikan posisi kejadian pertama True(ini hanya sebagian dari kode saya):

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]

Ini hanya mengembalikan "4"

Amon
sumber

Jawaban:

118

Gunakan enumerate, list.indexmengembalikan indeks kecocokan pertama yang ditemukan.

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

Untuk daftar besar, akan lebih baik menggunakan 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
Ashwini Chaudhary
sumber
Ahh begitu, saya melihat beberapa pertanyaan serupa memberitahu saya untuk menggunakan enumerate, tapi saya kira saya salah menggunakannya. Saya mengatur daftar sama dengan x, lalu melakukan enumerate(x)tetapi saya kira yang saya lakukan hanyalah menghitung 4? Itukah yang terjadi? Terima kasih atas bantuannya
Amon
Juga apa yang terjadi ketika Anda melakukan i for i, xpemahaman daftar? Saya hanya terbiasa melihat i for imisalnya, atau format serupa, apa fungsinya x? Terima kasih
Amon
1
@Amon enumeratemengembalikan tupel (ind, nilai) selama loop, sekarang kita dapat menetapkan item dari tuple untuk dua variabel menggunakan: i, x = (ind, value). Inilah tepatnya yang terjadi dalam lingkaran itu.
Ashwini Chaudhary
Oh, saya mengerti apa yang terjadi sekarang. Terima kasih banyak atas bantuannya!
Amon
Untuk siapa pun yang menggunakan Python3, dalam itertools.compresssolusinya, ubah xrangemenjadi range. ( xrangediubah namanya menjadi rangedi Python 3.)
MehmedB
64

Jika Anda memiliki numpy tersedia:

>>> 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])
jterrace
sumber
8
Perhatikan bahwa ini mengembalikan tupel yang membutuhkan np.where(states)[0]untuk benar-benar menggunakan hasil
Rufus
17

TL; DR : gunakan np.wherekarena ini adalah opsi tercepat. Pilihan Anda adalah np.where, itertools.compress, dan list comprehension.

Lihat perbandingan mendetail di bawah ini, di mana ia dapat dilihat np.wheremengungguli keduanya itertools.compressdan jugalist 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
  • Metode 1: Menggunakan 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)
  • Metode 2: Menggunakan itertools.compress
>>> %timeit list(compress(range(len(t)), t))
210 µs ± 704 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)
  • Metode 3 (metode tercepat): Menggunakan numpy.where
>>> %timeit np.where(t)
179 µs ± 593 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Meysam Sadeghi
sumber
2

Anda dapat menggunakan filter untuk itu:

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

Di rangesini menyebutkan elemen dari daftar Anda dan karena kami hanya menginginkan yang self.statesada True, kami menerapkan filter berdasarkan kondisi ini.

Untuk Python> 3.0:

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

sashkello
sumber
1

Gunakan cara pemahaman kamus,

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

Memasukkan:

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

Keluaran:

{4: True, 5: True, 7: True}
Pemula
sumber
3
Ini adalah pemahaman dikt, bukan pemahaman daftar.
Ashwini Chaudhary
1

Menggunakan perkalian bijak dan satu set:

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

Keluaran: {4, 5, 7}

Nate
sumber
1

Cukup lakukan ini:

def which_index(self):
    return [
        i for i in range(len(self.states))
        if self.states[i] == True
    ]
ArnabJyoti Thakuria
sumber
Terima kasih atas kontribusi Anda dan selamat datang di StackOverflow. Namun, harap baca Bantuan Pengeditan untuk meningkatkan pemformatan Anda, dan juga menambahkan beberapa penjelasan ke kode Anda. Terima kasih!
Akankah