Saya ingin melakukan sesuatu yang mirip dengan ini:
>>> x = [1,2,3,4,5,6,7,8,9,0]
>>> x
[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
>>> y = [1,3,5,7,9]
>>> y
[1, 3, 5, 7, 9]
>>> y - x # (should return [2,4,6,8,0])
Tapi ini tidak didukung oleh daftar python Apa cara terbaik untuk melakukannya?
Jawaban:
Gunakan pemahaman daftar:
Jika Anda ingin menggunakan
-
sintaks infix, Anda bisa melakukan:Anda kemudian dapat menggunakannya seperti:
Tetapi jika Anda tidak benar-benar membutuhkan properti daftar (misalnya, memesan), cukup gunakan set sebagai jawaban yang disarankan.
sumber
list
untuk nama variabel karena bayanganlist
konstruktor. Jika Anda menggunakan 'daftar', silakan mendahului dengan garis bawah. Juga, dengan menjatuhkannya*
, Anda memecahkan kode saya ...[1,1,2,2] - [1,2]
Anda akan mendapatkan daftar kosong.[1,1,2,2] - [2]
memberi[1,1]
Jadi bukan benar-benar daftar substraksi, itu lebih seperti "Daftar dari Daftar X tanpa elemen dari set Y " .y
menjadiset
sebelum setiap cek (yang biayanya mirip dengan karya asli). Anda harus melakukan diyset = set(y)
luar listcomp, kemudian mengujiif item not in yset
, atau sebagai peretasan yang mengerikan, melakukan[item for yset in [set(y)] for item in x if item not in yset]
yang menyalahgunakan daftar susunan bersarang untuk menyimpan cacheyset
sebagai satu-baris. Solusi one-liner yang sedikit kurang jelek yang berkinerja cukup akan digunakanlist(itertools.filterfalse(set(y).__contains__, x))
karena argumen untukfilterfalse
hanya dibangun sekali.Gunakan setel perbedaan
Atau Anda mungkin hanya memiliki set x dan y sehingga Anda tidak perlu melakukan konversi apa pun.
sumber
TypeError: unhashable type: 'dict'
Itu adalah operasi "atur pengurangan". Gunakan struktur data yang ditetapkan untuk itu.
Dengan Python 2.7:
Keluaran:
sumber
jika duplikat dan memesan barang bermasalah:
[i for i in a if not i in b or b.remove(i)]
sumber
O(m * n)
runtime (dan saya merasa ngeri setiap kali listcomp menyertakan efek samping); Anda dapat meningkatkannya menggunakancollections.Counter
untuk mendapatkanO(m + n)
runtime.Untuk banyak kasus penggunaan, jawaban yang Anda inginkan adalah:
Ini adalah gabungan antara jawaban aaronasterling dan jawaban quantumSoup .
Versi aaronasterling melakukan
len(y)
perbandingan item untuk setiap elemenx
, sehingga dibutuhkan waktu kuadratik. Versi quantumSoup menggunakan set, sehingga ia melakukan pencarian set waktu konstan tunggal untuk setiap elemen dalamx
—tapi, karena ia mengubah keduanyax
dany
menjadi set, ia kehilangan urutan elemen Anda.Dengan mengubah hanya
y
menjadi satu set, dan mengulanginyax
secara berurutan, Anda mendapatkan yang terbaik dari kedua dunia — waktu linier, dan pelestarian pesanan. *Namun, ini masih memiliki masalah dari versi quantumSoup: Ini membutuhkan elemen Anda untuk dapat hashable. Itu cukup banyak dibangun ke dalam sifat set. ** Jika Anda mencoba, misalnya, kurangi daftar dicts dari daftar dicts lain, tetapi daftar untuk mengurangi besar, apa yang Anda lakukan?
Jika Anda dapat menghias nilai-nilai Anda dengan cara yang dapat di-hashable, itu memecahkan masalah. Misalnya, dengan kamus datar yang nilainya sendiri dapat diunggah:
Jika tipe Anda sedikit lebih rumit (misalnya, sering Anda berurusan dengan nilai yang kompatibel dengan JSON, yang dapat hashable, atau daftar atau dikte yang nilainya secara rekursif adalah jenis yang sama), Anda masih dapat menggunakan solusi ini. Tetapi beberapa tipe tidak dapat dikonversi menjadi hashable apa pun.
Jika barang Anda tidak, dan tidak dapat dibuat, dapat hashable, tetapi mereka dapat dibandingkan, Anda setidaknya bisa mendapatkan waktu log-linear (
O(N*log M)
, yang jauh lebih baik daripadaO(N*M)
waktu solusi daftar, tetapi tidak sebagus yangO(N+M)
saat solusi set) dengan menyortir dan menggunakanbisect
:Jika barang Anda tidak dapat dipilah atau sebanding, maka Anda terjebak dengan solusi kuadratik.
* Perhatikan bahwa Anda juga bisa melakukan ini dengan menggunakan sepasang
OrderedSet
benda, yang untuknya Anda dapat menemukan resep dan modul pihak ketiga. Tapi saya pikir ini lebih sederhana.** Alasan set lookup adalah waktu yang konstan adalah yang harus dilakukan hanyalah nilai hash dan lihat apakah ada entri untuk hash itu. Jika tidak dapat mengaitkan nilainya, ini tidak akan berhasil.
sumber
Mencari nilai di set lebih cepat daripada mencari di daftar:
Saya percaya ini akan skala sedikit lebih baik daripada:
Keduanya mempertahankan urutan daftar.
sumber
set(y)
dan tidak dikonversiy
ke set baru di setiap loop? Jika tidak, Anda akan lebih jawaban kebutuhan abarnert ini:ys = set(y); [i for i in x if i not in ys]
.if i not in set(y)
membutuhkan waktu 25% lebih lama dariif i not in y
(di manay
ada daftar). Pra-konversi set membutuhkan waktu 55% lebih sedikit. Diuji dengan cukup pendekx
dany
, tetapi perbedaan harus lebih diucapkan dengan panjang, jika ada.y
untuk setiap elemenx
; kecuali perbandingan kesetaraan benar-benar mahal relatif terhadap perhitungan hash, ini akan selalu kalah dari biasaitem not in y
.Jika daftar memungkinkan elemen duplikat, Anda dapat menggunakan Penghitung dari koleksi:
Jika Anda perlu mempertahankan urutan elemen dari x:
sumber
Counter.subtract
tidak menghapus elemen bernilai nol (-
dan-=
lakukan, tetapi tidaksubtract
), jadi Anda tidak akan pernah berhenti menghapus elemen. Anda ingin menggantinot v in c
dengannot c[v]
(yang mengembalikan nol untuk elemen yang tidak ada, sehingga Anda dapat dengan aman menguji pengembalian untuk "noliness" melaluinot
).Saya pikir cara termudah untuk mencapai ini adalah dengan menggunakan set ().
sumber
Solusi lain memiliki satu dari beberapa masalah:
x = [1, 2, 2, 2]
dany = [2, 2]
mereka mengonversiy
menjadiset
, dan menghapus semua elemen yang cocok ([1]
hanya menyisakan ) atau menghapus salah satu dari setiap elemen unik (meninggalkan[1, 2, 2]
), ketika perilaku yang tepat akan menghapus2
dua kali, pergi[1, 2]
, atauO(m * n)
bekerja, di mana solusi optimal dapatO(m + n)
bekerjaAlain berada di jalur yang benar dengan
Counter
memecahkan # 2 dan # 3, tetapi solusi itu akan kehilangan pemesanan. Solusi yang menjaga ketertiban (menghapusn
salinan pertama dari setiap nilai untukn
pengulangan dalamlist
nilai yang akan dihapus) adalah:Cobalah online!
Untuk membuatnya menghapus salinan terakhir dari setiap elemen, cukup ubah
for
loop kefor val in reversed(x):
dan tambahkanout.reverse()
segera setelah keluar darifor
loop.Membangun
Counter
adalahO(n)
dalam haly
's panjang, iterasix
adalahO(n)
dalam halx
' s panjang, danCounter
pengujian keanggotaan dan mutasi adalahO(1)
, sementaralist.append
diamortisasiO(1)
(diberikanappend
bisaO(n)
, tapi bagi banyakappend
s, secara keseluruhan besar-O rata-rataO(1)
sejak lebih sedikit dan lebih sedikit dari mereka membutuhkan realokasi), sehingga keseluruhan pekerjaan yang dilakukan adalahO(m + n)
.Anda juga dapat menguji untuk menentukan apakah ada elemen di dalamnya
y
yang tidak dihapus darix
pengujian:sumber
int
s ke dalam array panjang tetap) atau harus melakukan lebih dariO(m + n)
pekerjaan (misalnya big terbaik berikutnya -O akan membuat diurutkanlist
nilai unik / pasangan hitungan, mengubahO(1)
dict
pencarian menjadiO(log n)
pencarian biner, Anda akan membutuhkan nilai unik dengan jumlah mereka, bukan hanya mengurutkan nilai-nilai non-unik, karena jika tidak, Anda akan membayarO(n)
biaya untuk menghapus elemen dari yang diurutkanlist
).Coba ini.
sumber
Jawaban yang diberikan oleh @aaronasterling penampilan yang baik, bagaimanapun, tidak kompatibel dengan antarmuka default daftar:
x = MyList(1, 2, 3, 4)
vsx = MyList([1, 2, 3, 4])
. Dengan demikian, kode di bawah ini dapat digunakan sebagai ramah daftar python:Contoh:
sumber
Saya pikir ini lebih cepat:
sumber
Contoh ini mengurangi dua daftar:
sumber