Python Sets vs Lists

187

Dalam Python, struktur data mana yang lebih efisien / cepat? Dengan asumsi bahwa pesanan tidak penting bagi saya dan saya akan tetap memeriksa duplikatnya, apakah Python set lebih lambat dari daftar Python?

Mantas Vidutis
sumber

Jawaban:

231

Itu tergantung pada apa yang ingin Anda lakukan dengannya.

Set secara signifikan lebih cepat ketika datang untuk menentukan apakah suatu objek hadir dalam set (seperti pada x in s), tetapi lebih lambat dari daftar ketika datang untuk mengulangi isinya.

Anda dapat menggunakan modul timeit untuk melihat mana yang lebih cepat untuk situasi Anda.

Michael Aaron Safyan
sumber
4
Untuk poin Anda: "Set secara signifikan lebih cepat", apa implementasi mendasar yang membuatnya lebih cepat?
pertukaran berlebihan
Bahasa scripting suka menyembunyikan implementasi yang mendasarinya, tetapi kesederhanaan yang tampak ini tidak selalu merupakan hal yang baik, Anda memang membutuhkan kesadaran 'struktur data' ketika Anda merancang perangkat lunak.
Christophe Roussy
4
Set tidak jauh lebih lambat dari daftar saat iterasi.
omerfarukdogan
39
Set dan daftar keduanya memiliki iterasi waktu linier. Mengatakan bahwa satu "lebih lambat" daripada yang lain salah arah dan telah membingungkan programmer baru yang membaca jawaban ini.
habnabit
@habnabit jika Anda mengatakan bahwa mereka berdua memiliki iterasi waktu linier. Apakah ini berarti mereka memiliki waktu iterasi yang sama? Apa bedanya?
Mohammed Noureldin
153

Daftar sedikit lebih cepat daripada yang ditetapkan ketika Anda hanya ingin mengulangi nilai.

Namun, set secara signifikan lebih cepat daripada daftar jika Anda ingin memeriksa apakah suatu item terkandung di dalamnya. Mereka hanya dapat berisi barang-barang unik.

Ternyata tuple berkinerja hampir sama persis dengan daftar, kecuali untuk keabadiannya.

Iterasi

>>> def iter_test(iterable):
...     for i in iterable:
...         pass
...
>>> from timeit import timeit
>>> timeit(
...     "iter_test(iterable)",
...     setup="from __main__ import iter_test; iterable = set(range(10000))",
...     number=100000)
12.666952133178711
>>> timeit(
...     "iter_test(iterable)",
...     setup="from __main__ import iter_test; iterable = list(range(10000))",
...     number=100000)
9.917098999023438
>>> timeit(
...     "iter_test(iterable)",
...     setup="from __main__ import iter_test; iterable = tuple(range(10000))",
...     number=100000)
9.865639209747314

Tentukan apakah suatu benda ada

>>> def in_test(iterable):
...     for i in range(1000):
...         if i in iterable:
...             pass
...
>>> from timeit import timeit
>>> timeit(
...     "in_test(iterable)",
...     setup="from __main__ import in_test; iterable = set(range(1000))",
...     number=10000)
0.5591847896575928
>>> timeit(
...     "in_test(iterable)",
...     setup="from __main__ import in_test; iterable = list(range(1000))",
...     number=10000)
50.18339991569519
>>> timeit(
...     "in_test(iterable)",
...     setup="from __main__ import in_test; iterable = tuple(range(1000))",
...     number=10000)
51.597304821014404
Ellis Percival
sumber
6
Saya telah menemukan bahwa (Inisialisasi set -> 5.5300979614257812) (Inisialisasi daftar -> 1.8846848011016846) (Inisialisasi tuple -> 1.8730108737945557) Item berukuran 10.000 pada core intel i5 quad core dengan RAM 12GB. Ini harus dipertimbangkan juga.
ThePracticalOne
4
Saya telah memperbarui kode untuk menghapus pembuatan objek sekarang. Fase pengaturan loop timeit hanya dipanggil sekali ( docs.python.org/2/library/timeit.html#timeit.Timer.timeit ).
Ellis Percival
7

Daftar kinerja:

>>> import timeit
>>> timeit.timeit(stmt='10**6 in a', setup='a = range(10**6)', number=100000)
0.008128150348026608

Setel kinerja:

>>> timeit.timeit(stmt='10**6 in a', setup='a = set(range(10**6))', number=100000)
0.005674857488571661

Anda mungkin ingin mempertimbangkan Tuples karena mirip dengan daftar tetapi tidak dapat dimodifikasi. Mereka mengambil sedikit lebih sedikit memori dan lebih cepat untuk diakses. Mereka tidak fleksibel tetapi lebih efisien daripada daftar. Penggunaan normal mereka adalah untuk berfungsi sebagai kunci kamus.

Set juga struktur urutan tetapi dengan dua perbedaan dari daftar dan tupel. Meskipun set memang memiliki perintah, perintah itu sewenang-wenang dan tidak di bawah kendali programmer. Perbedaan kedua adalah bahwa elemen-elemen dalam himpunan harus unik.

setMenurut definisi. [ python | wiki ].

>>> x = set([1, 1, 2, 2, 3, 3])
>>> x
{1, 2, 3}
pengguna2601995
sumber
4
Pertama, Anda harus memperbarui ke settautan tipe bawaan ( docs.python.org/2/library/stdtypes.html#set ) bukan setspustaka yang sudah usang . Kedua, "Set juga merupakan struktur urutan", baca yang berikut dari tautan tipe bawaan: "Menjadi koleksi yang tidak terurut, set tidak mencatat posisi elemen atau urutan penyisipan. Dengan demikian, set tidak mendukung pengindeksan, pengirisan, atau lainnya. perilaku seperti urutan. "
Seaux
7
rangetidak list. rangeadalah kelas khusus dengan __contains__metode sulap khusus .
Ryne Wang
@RyneWang ini benar, tetapi hanya untuk Python3. Dalam rentang Python2 mengembalikan daftar normal (itu sebabnya ada hal-hal mengerikan seperti xrange)
Manoel Vilela
7

Setmenang karena cek 'berisi' hampir instan: https://en.wikipedia.org/wiki/Hash_table

Daftar implementasi: biasanya sebuah array, level rendah dekat dengan logam, baik untuk iterasi dan akses acak dengan indeks elemen.

Atur implementasi: https://en.wikipedia.org/wiki/Hash_table , ia tidak mengulangi pada daftar, tetapi menemukan elemen dengan menghitung hash dari kunci, jadi itu tergantung pada sifat elemen kunci dan hash fungsi. Mirip dengan apa yang digunakan untuk dict. Saya menduga listbisa lebih cepat jika Anda memiliki sangat sedikit elemen (<5), semakin besar elemen menghitung semakin baik setkinerjanya untuk cek berisi. Ini juga cepat untuk penambahan dan penghapusan elemen. Juga selalu ingat bahwa membangun set memiliki biaya!

CATATAN : Jika listsudah diurutkan, pencarian listbisa sangat cepat, tetapi untuk kasus biasa a setlebih cepat dan lebih mudah untuk berisi cek.

Christophe Roussy
sumber
8
Dekat dengan logam? Apa artinya itu dalam konteks Python? Bagaimana daftar lebih dekat ke logam daripada satu set?
roganjosh
@roganjosh, python masih berjalan pada mesin dan beberapa implementasi seperti daftar sebagai 'array' lebih dekat dengan apa yang baik pada perangkat keras: stackoverflow.com/questions/176011/… , tetapi selalu tergantung pada apa yang ingin Anda capai, itu Adalah baik untuk mengetahui sedikit tentang implementasi, bukan hanya abstraksi.
Christophe Roussy
2

tl; dr

Struktur data (DS) penting karena mereka digunakan untuk melakukan operasi pada data yang pada dasarnya menyiratkan: mengambil beberapa input , memprosesnya , dan memberikan kembali output .

Beberapa struktur data lebih bermanfaat daripada yang lain dalam beberapa kasus tertentu. Oleh karena itu, sangat tidak adil untuk bertanya (DS) mana yang lebih efisien / cepat. Ini seperti menanyakan alat mana yang lebih efisien antara pisau dan garpu. Maksud saya semua tergantung situasi.

Daftar

Daftar adalah urutan yang dapat berubah , biasanya digunakan untuk menyimpan koleksi item yang homogen .

Set

Objek yang ditetapkan adalah kumpulan objek hashable berbeda yang tidak berurutan . Biasanya digunakan untuk menguji keanggotaan, menghapus duplikat dari urutan, dan menghitung operasi matematika seperti persimpangan, gabungan, perbedaan, dan perbedaan simetris.

Pemakaian

Dari beberapa jawaban, jelas bahwa daftar lebih cepat daripada satu set ketika mengulangi nilai-nilai. Di sisi lain, satu set lebih cepat dari daftar ketika memeriksa apakah suatu item terkandung di dalamnya. Oleh karena itu, satu-satunya hal yang dapat Anda katakan adalah bahwa daftar lebih baik daripada satu set untuk beberapa operasi tertentu dan sebaliknya.

lmiguelvargasf
sumber
2

Saya tertarik pada hasil ketika memeriksa, dengan CPython, jika nilainya adalah salah satu dari sejumlah kecil literal. setmenang dalam Python 3 vs tuple, listdan or:

from timeit import timeit

def in_test1():
  for i in range(1000):
    if i in (314, 628):
      pass

def in_test2():
  for i in range(1000):
    if i in [314, 628]:
      pass

def in_test3():
  for i in range(1000):
    if i in {314, 628}:
      pass

def in_test4():
  for i in range(1000):
    if i == 314 or i == 628:
      pass

print("tuple")
print(timeit("in_test1()", setup="from __main__ import in_test1", number=100000))
print("list")
print(timeit("in_test2()", setup="from __main__ import in_test2", number=100000))
print("set")
print(timeit("in_test3()", setup="from __main__ import in_test3", number=100000))
print("or")
print(timeit("in_test4()", setup="from __main__ import in_test4", number=100000))

Keluaran:

tuple
4.735646052286029
list
4.7308746771886945
set
3.5755991376936436
or
4.687681658193469

Untuk 3 hingga 5 liter, setmasih menang dengan selisih yang lebar, dan ormenjadi yang paling lambat.

Dalam Python 2, setselalu yang paling lambat. oradalah tercepat selama 2 sampai 3 literal, dan tupledan listlebih cepat dengan 4 atau lebih literal. Aku tidak bisa membedakan kecepatan tuplevs list.

Ketika nilai-nilai untuk menguji di-cache dalam variabel global di luar fungsi, alih-alih membuat literal dalam loop, setdimenangkan setiap waktu, bahkan dalam Python 2.

Hasil ini berlaku untuk 64-bit CPython pada Core i7.

Pedro Gimeno
sumber
0

Saya akan merekomendasikan implementasi Set di mana use case terbatas untuk referensi atau mencari keberadaan dan implementasi Tuple di mana use case mengharuskan Anda untuk melakukan iterasi. Daftar adalah implementasi tingkat rendah dan membutuhkan overhead memori yang signifikan.


sumber
1
Memang, perbedaan yang tepat antara kapan harus menggunakan Sets dan kapan harus menggunakan Tuple memang sangat penting. Saya tidak akan khawatir tentang overhead memori yang terlibat, jejak kaki kecuali saya membuat skrip API tingkat rendah.
0
from datetime import datetime
listA = range(10000000)
setA = set(listA)
tupA = tuple(listA)
#Source Code

def calc(data, type):
start = datetime.now()
if data in type:
print ""
end = datetime.now()
print end-start

calc(9999, listA)
calc(9999, tupA)
calc(9999, setA)

Output setelah membandingkan 10 iterasi untuk semua 3: Perbandingan

Harshal SG
sumber
0

Set lebih cepat, lebih dari itu Anda mendapatkan lebih banyak fungsi dengan set, seperti katakanlah Anda memiliki dua set:

set1 = {"Harry Potter", "James Bond", "Iron Man"}
set2 = {"Captain America", "Black Widow", "Hulk", "Harry Potter", "James Bond"}

Kami dapat dengan mudah bergabung dengan dua set:

set3 = set1.union(set2)

Cari tahu apa yang sama pada keduanya:

set3 = set1.intersection(set2)

Cari tahu apa yang berbeda dari keduanya:

set3 = set1.difference(set2)

Dan banyak lagi! Coba saja, mereka menyenangkan! Terlebih lagi jika Anda harus mengerjakan nilai yang berbeda dalam 2 daftar atau nilai umum dalam 2 daftar, saya lebih suka mengonversi daftar Anda menjadi set, dan banyak programmer melakukannya dengan cara itu. Semoga ini bisa membantu Anda :-)

Shakhyar Gogoi
sumber