Cara tercepat untuk memeriksa apakah nilai yang ada di daftar

Apa cara tercepat untuk mengetahui apakah nilai yang ada dalam list (daftar dengan jutaan dari nilai-nilai di dalamnya) dan apa yang index-nya adalah?

Aku tahu bahwa semua nilai-nilai dalam daftar yang unik seperti dalam contoh ini.

Metode pertama yang saya coba adalah (3.8 detik pada kode):

a = [4,2,3,1,5,6]

if a.count(7) == 1:
    b=a.index(7)
    "Do something with variable b"

Metode kedua yang saya coba adalah (2x lebih cepat: 1.9 detik untuk saya yang sebenarnya kode):

a = [4,2,3,1,5,6]

try:
    b=a.index(7)
except ValueError:
    "Do nothing"
else:
    "Do something with variable b"

Metode yang diusulkan dari Stack Overflow pengguna (2.74 detik untuk saya yang sebenarnya kode):

a = [4,2,3,1,5,6]
if 7 in a:
    a.index(7)

Pada kode, metode pertama mengambil 3.81 sec dan metode kedua membutuhkan 1.88 detik. It's sebuah peningkatan yang baik, tetapi:

I'm pemula dengan Python/scripting, dan apakah ada cara yang lebih cepat untuk melakukan hal yang sama dan lebih menghemat waktu proses?

Lebih spesifik penjelasan untuk aplikasi saya:

Di Blender API saya dapat mengakses daftar partikel:

particles = [1, 2, 3, 4, etc.]

Dari sana, saya dapat mengakses partikel's lokasi:

particles[x].location = [x,y,z]

Dan untuk setiap partikel I tes jika seorang tetangga yang ada dengan mencari partikel masing-masing lokasi seperti:

if [x+1,y,z] in particles.location
    "Find the identity of this neighbour particle in x:the particle's index
    in the array"
    particles.index([x+1,y,z])
Mengomentari pertanyaan (5)
Larutan
7 in a

Yang paling jelas dan tercepat untuk melakukan itu.

Anda juga dapat mempertimbangkan untuk menggunakan set, tapi membangun yang membedakan dari daftar anda dapat mengambil lebih banyak waktu lebih cepat dari keanggotaan pengujian akan menyimpan. Satu-satunya cara untuk memastikan adalah untuk acuan baik. (ini juga tergantung pada operasi apa yang anda butuhkan)

Komentar (7)

Seperti yang dinyatakan oleh orang lain, di bisa sangat lambat untuk daftar besar. Berikut ini adalah beberapa perbandingan dari pertunjukan di, set dan dua. Catat waktu (dalam detik) dalam skala log.

Kode untuk pengujian:

import random
import bisect
import matplotlib.pyplot as plt
import math
import time

def method_in(a,b,c):
    start_time = time.time()
    for i,x in enumerate(a):
        if x in b:
            c[i] = 1
    return(time.time()-start_time)   

def method_set_in(a,b,c):
    start_time = time.time()
    s = set(b)
    for i,x in enumerate(a):
        if x in s:
            c[i] = 1
    return(time.time()-start_time)

def method_bisect(a,b,c):
    start_time = time.time()
    b.sort()
    for i,x in enumerate(a):
        index = bisect.bisect_left(b,x)
        if index < len(a):
            if x == b[index]:
                c[i] = 1
    return(time.time()-start_time)

def profile():
    time_method_in = []
    time_method_set_in = []
    time_method_bisect = []

    Nls = [x for x in range(1000,20000,1000)]
    for N in Nls:
        a = [x for x in range(0,N)]
        random.shuffle(a)
        b = [x for x in range(0,N)]
        random.shuffle(b)
        c = [0 for x in range(0,N)]

        time_method_in.append(math.log(method_in(a,b,c)))
        time_method_set_in.append(math.log(method_set_in(a,b,c)))
        time_method_bisect.append(math.log(method_bisect(a,b,c)))

    plt.plot(Nls,time_method_in,marker='o',color='r',linestyle='-',label='in')
    plt.plot(Nls,time_method_set_in,marker='o',color='b',linestyle='-',label='set')
    plt.plot(Nls,time_method_bisect,marker='o',color='g',linestyle='-',label='bisect')
    plt.xlabel('list size', fontsize=18)
    plt.ylabel('log(time)', fontsize=18)
    plt.legend(loc = 'upper left')
    plt.show()
Komentar (4)

Anda bisa menempatkan barang-barang anda ke set. Mengatur pencarian yang sangat efisien.

Coba:

s = set(a)
if 7 in s:
  # do stuff

edit komentar anda mengatakan bahwa anda'd untuk mendapatkan indeks dari elemen. Sayangnya, set tidak memiliki gagasan tentang posisi elemen. Alternatif adalah untuk pra-urutkan daftar anda dan kemudian gunakan pencarian biner setiap waktu yang anda butuhkan untuk menemukan elemen.

Komentar (3)
def check_availability(element, collection: iter):
    return element in collection

Penggunaan ****

check_availability('a', [1,2,3,4,'a','b','c'])

Saya percaya ini adalah cara tercepat untuk mengetahui jika a memilih nilai dalam array.

Komentar (5)
a = [4,2,3,1,5,6]

index = dict((y,x) for x,y in enumerate(a))
try:
   a_index = index[7]
except KeyError:
   print "Not found"
else:
   print "found"

Ini hanya akan menjadi ide yang baik jika doesn't perubahan, dan dengan demikian kita dapat melakukan dict() bagian sekali dan kemudian menggunakannya berulang kali. Jika tidak berubah, mohon berikan detail lebih lanjut tentang apa yang anda lakukan.

Komentar (3)

Kedengarannya seperti aplikasi anda mungkin mendapatkan keuntungan dari penggunaan Mekar Filter struktur data.

Singkatnya, mekar filter look-up dapat memberitahu anda dengan sangat cepat jika nilai yang PASTI TIDAK hadir dalam satu set. Jika tidak, anda dapat melakukan lebih lambat look-up untuk mendapatkan indeks nilai yang MUNGKIN ada di dalam daftar. Jadi jika aplikasi anda cenderung untuk mendapatkan "tidak ditemukan" hasilnya jauh lebih sering maka "ditemukan" hasilnya, anda mungkin melihat kecepatan dengan menambahkan Mekar Filter.

Untuk rincian, Wikipedia memberikan gambaran yang baik tentang bagaimana Mekar Filter kerja, dan pencarian web untuk "python mekar filter perpustakaan" akan memberikan setidaknya beberapa berguna implementasi.

Komentar (0)

Diketahui bahwa dalam operator tes tidak hanya kesetaraan (==) tapi juga identitas (adalah), dalam logika `daftar ini adalah kira-kira setara dengan berikut (it's benar-benar ditulis dalam C dan tidak Python meskipun, setidaknya di CPython):

untuk elemen dalam s: jika elemen target:

cepat memeriksa identitas menyiratkan kesetaraan

return True jika elemen == target:

lebih lambat memeriksa sebenarnya kesetaraan

return True return False

Dalam sebagian besar keadaan ini detail yang tidak relevan, tetapi dalam beberapa keadaan mungkin meninggalkan Python pemula terkejut, misalnya, numpy.NAN memiliki properti yang tidak biasa menjadi tidak sama dengan dirinya sendiri:

>>> import numpy
>>> numpy.NAN == numpy.NAN
False
>>> numpy.NAN is numpy.NAN
True
>>> numpy.NAN in [numpy.NAN]
True

Untuk membedakan antara kasus ini tidak anda bisa menggunakan setiap() seperti:

>>> lst = [numpy.NAN, 1 , 2]
>>> any(element == numpy.NAN for element in lst)
False
>>> any(element is numpy.NAN for element in lst)
True 

Catatan di logika daftar dengansetiap()` akan sama:

any(element is target or element == target for element in lst)

Namun, saya harus menekankan bahwa ini adalah kasus tepi, dan untuk sebagian besar kasus dalam operator ini sangat optimal dan tepat apa yang anda inginkan tentu saja (baik dengan daftar atau dengan set).

Komentar (1)

Atau menggunakan __memuat__:

sequence.__contains__(value)

Demo:

>>> l=[1,2,3]
>>> l.__contains__(3)
True
>>> 
Komentar (0)

Ini bukan kode, tetapi algoritma untuk pencarian cepat.

Jika daftar anda dan nilai anda yang mencari semua angka-angka, ini cukup mudah. Jika string: lihat di bawah:

  • -Biarkan "n" menjadi panjang daftar
  • -Langkah opsional: jika anda membutuhkan indeks dari elemen: menambahkan kolom kedua untuk daftar dengan saat ini indeks dari elemen-elemen (0 sampai n-1) - lihat nanti
  • Pesanan anda klik disini atau copy dari itu (.sort())
  • Loop melalui:
  • Bandingkan nomor anda ke n/2 elemen daftar
  • Jika lebih besar, loop lagi antara indeks n/2-n
  • Jika lebih kecil, lingkaran lagi antara indeks 0-n/2
  • Jika sama: anda menemukannya
  • Menjaga penyempitan daftar sampai anda telah menemukan itu atau hanya memiliki 2 angka (di bawah dan di atas salah satu yang anda cari)
  • Ini akan menemukan setiap elemen dalam pada kebanyakan 19 langkah-langkah untuk daftar 1.000.000 (log(2)n harus tepat)

Jika anda juga membutuhkan posisi asli dari nomor anda, mencarinya di kedua, indeks kolom.

Jika daftar ini tidak dibuat dari angka-angka, metode ini masih bekerja dan akan menjadi yang tercepat, tetapi anda mungkin perlu untuk menentukan fungsi yang dapat membandingkan/order string.

Tentu saja, ini membutuhkan investasi diurutkan() metode, tetapi jika anda terus menggunakan kembali daftar yang sama untuk memeriksa, mungkin worth it.

Komentar (1)

@Winston Ewert's solusi hasil besar kecepatan-up untuk daftar yang sangat besar, tapi ini stackoverflow jawaban menunjukkan bahwa try:/kecuali:/lain: membangun akan melambat jika kecuali cabang lebih sering tercapai. Alternatif adalah untuk mengambil keuntungan dari .get() metode untuk dict:

`` a = [4,2,3,1,5,6]

indeks = dict((y, x) untuk x, y dalam menghitung(a))

b = indeks.mendapatkan(7, Tidak ada) jika b tidak Tidak ada: "Melakukan sesuatu dengan variabel b" ``

The .mendapatkan(kunci, default) metode ini hanya untuk kasus ketika anda dapat't jaminan kunci akan di dict. Jika kunci adalah, ini mengembalikan nilai (seperti yang akan dict[key]), tetapi ketika itu tidak, .get() mengembalikan nilai default anda (di sini None). Anda perlu memastikan bahwa dalam kasus ini yang dipilih default tidak akan di a.

Komentar (0)

Pertanyaan awal adalah:

Apa adalah cara tercepat untuk mengetahui apakah nilai yang ada dalam list (daftar dengan jutaan dari nilai-nilai di dalamnya) dan apa yang index-nya adalah?

Dengan demikian ada dua hal untuk menemukan:

  1. adalah salah satu item dalam daftar, dan
  2. apa index (jika di daftar).

Terhadap hal ini, aku dimodifikasi @xslittlegrass kode untuk menghitung indeks dalam semua kasus, dan menambahkan metode tambahan.

Hasil

Metode ini adalah:

  1. dalam-pada dasarnya jika x di b: kembali b.index(x)
  2. coba-coba/tangkap di b.index(x) (skips harus memeriksa jika x di b)
  3. set--pada dasarnya jika x di set(b): kembali b.index(x)
  4. membagi dua--sort b dengan indeks, pencarian biner untuk x di diurutkan(b). Catatan mod dari @xslittlegrass yang kembali turun di diurutkan b, daripada aslinya b)
  5. reverse--membentuk lingkaran terbalik kamus d untuk b; kemudian d[x] menyediakan indeks x.

Hasil penelitian menunjukkan bahwa metode 5 tercepat.

Menariknya coba ** dan set** metode yang sama dalam waktu.


Kode Uji

import random
import bisect
import matplotlib.pyplot as plt
import math
import timeit
import itertools

def wrapper(func, *args, **kwargs):
    " Use to produced 0 argument function for call it"
    # Reference https://www.pythoncentral.io/time-a-python-function/
    def wrapped():
        return func(*args, **kwargs)
    return wrapped

def method_in(a,b,c):
    for i,x in enumerate(a):
        if x in b:
            c[i] = b.index(x)
        else:
            c[i] = -1
    return c

def method_try(a,b,c):
    for i, x in enumerate(a):
        try:
            c[i] = b.index(x)
        except ValueError:
            c[i] = -1

def method_set_in(a,b,c):
    s = set(b)
    for i,x in enumerate(a):
        if x in s:
            c[i] = b.index(x)
        else:
            c[i] = -1
    return c

def method_bisect(a,b,c):
    " Finds indexes using bisection "

    # Create a sorted b with its index
    bsorted = sorted([(x, i) for i, x in enumerate(b)], key = lambda t: t[0])

    for i,x in enumerate(a):
        index = bisect.bisect_left(bsorted,(x, ))
        c[i] = -1
        if index < len(a):
            if x == bsorted[index][0]:
                c[i] = bsorted[index][1]  # index in the b array

    return c

def method_reverse_lookup(a, b, c):
    reverse_lookup = {x:i for i, x in enumerate(b)}
    for i, x in enumerate(a):
        c[i] = reverse_lookup.get(x, -1)
    return c

def profile():
    Nls = [x for x in range(1000,20000,1000)]
    number_iterations = 10
    methods = [method_in, method_try, method_set_in, method_bisect, method_reverse_lookup]
    time_methods = [[] for _ in range(len(methods))]

    for N in Nls:
        a = [x for x in range(0,N)]
        random.shuffle(a)
        b = [x for x in range(0,N)]
        random.shuffle(b)
        c = [0 for x in range(0,N)]

        for i, func in enumerate(methods):
            wrapped = wrapper(func, a, b, c)
            time_methods[i].append(math.log(timeit.timeit(wrapped, number=number_iterations)))

    markers = itertools.cycle(('o', '+', '.', '>', '2'))
    colors = itertools.cycle(('r', 'b', 'g', 'y', 'c'))
    labels = itertools.cycle(('in', 'try', 'set', 'bisect', 'reverse'))

    for i in range(len(time_methods)):
        plt.plot(Nls,time_methods[i],marker = next(markers),color=next(colors),linestyle='-',label=next(labels))

    plt.xlabel('list size', fontsize=18)
    plt.ylabel('log(time)', fontsize=18)
    plt.legend(loc = 'upper left')
    plt.show()

profile()
Komentar (0)

Ini bekerja untuk saya: (daftar pemahaman, satu-liner)

[list_to_search_in.index(i) for i in list_from_which_to_search if i in list_to_search_in]

Aku punya list_to_search_in dengan semua item, dan ingin mengembalikan indeks dari item dalam list_from_which_to_search.

Ini kembali dalam berbagai daftar yang bagus.

Komentar (0)

Bagi saya itu adalah 0.030 detik (real), 0.026 detik (user), dan 0.004 detik (sys).

try:
print("Started")
x = ["a", "b", "c", "d", "e", "f"]

i = 0

while i < len(x):
    i += 1
    if x[i] == "e":
        print("Found")
except IndexError:
    pass
Komentar (0)

Kode untuk memeriksa apakah dua elemen ada dalam array yang sama dengan produk k:

n = len(arr1)
for i in arr1:
    if k%i==0:
        print(i)
Komentar (0)