Cukup banyak yang saya butuhkan untuk menulis sebuah program untuk memeriksa jika daftar telah duplikat dan jika itu tidak menghilangkan mereka dan kembali baru daftar dengan item yang tidak't digandakan/dihapus. Ini adalah apa yang saya miliki tapi jujur saya tidak tahu apa yang harus dilakukan.
def remove_duplicates():
t = ['a', 'b', 'c', 'd']
t2 = ['a', 'c', 'd']
for t in t2:
t.append(t.remove())
return t
Pendekatan yang umum untuk mendapatkan koleksi unik dari barang-barang adalah dengan menggunakan set
. Set unordered koleksi berbeda benda-benda. Untuk membuat satu set dari setiap iterable, anda hanya dapat menyebarkannya ke built-in set()
fungsi. Jika anda kemudian perlu daftar lagi, anda dapat pula lulus diatur ke daftar()
fungsi.
Contoh berikut harus mencakup apa pun yang anda coba lakukan:
>>> t = [1, 2, 3, 1, 2, 5, 6, 7, 8]
>>> t
[1, 2, 3, 1, 2, 5, 6, 7, 8]
>>> list(set(t))
[1, 2, 3, 5, 6, 7, 8]
>>> s = [1, 2, 3]
>>> list(set(t) - set(s))
[8, 5, 6, 7]
Seperti yang anda lihat dari contoh hasil, asli agar tidak dipertahankan. Seperti disebutkan di atas, set sendiri adalah unordered koleksi, sehingga urutan hilang. Ketika mengkonversi satu set kembali ke daftar, urutan sewenang-wenang dibuat.
Jika urutan ini penting untuk anda, maka anda akan harus menggunakan mekanisme yang berbeda. Yang sangat umum solusi untuk ini adalah untuk mengandalkan OrderedDict
untuk menjaga urutan tombol selama penyisipan:
>>> from collections import OrderedDict
>>> list(OrderedDict.fromkeys(t))
[1, 2, 3, 5, 6, 7, 8]
Mulai dengan Python 3.7, built-in kamus dijamin untuk menjaga penyisipan order juga, sehingga anda juga dapat menggunakannya secara langsung jika anda berada di Python 3.7 atau lambat (atau CPython 3.6):
>>> list(dict.fromkeys(t))
[1, 2, 3, 5, 6, 7, 8]
Catatan ini telah overhead membuat kamus pertama, dan kemudian membuat daftar dari itu. Jika anda tidak benar-benar perlu untuk menjaga ketertiban, anda lebih baik menggunakan satu set. Check out pertanyaan untuk rincian lebih lanjut dan cara-cara alternatif untuk menjaga agar ketika menghapus duplikat.
Akhirnya diketahui bahwa kedua set
serta OrderedDict
/dict
solusi membutuhkan barang-barang anda untuk menjadi hashable. Hal ini biasanya berarti bahwa mereka harus berubah. Jika anda memiliki untuk berurusan dengan barang-barang yang tidak hashable (misalnya daftar benda-benda), maka anda akan harus menggunakan pendekatan lambat di mana anda pada dasarnya akan memiliki untuk membandingkan setiap item dengan setiap item dalam nested loop.
Di Python 2.7, cara baru menghapus duplikat dari iterable sambil menjaga dalam urutan asli adalah:
>>> from collections import OrderedDict
>>> list(OrderedDict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']
Di Python 3.5, yang OrderedDict memiliki implementasi C. Saya timing menunjukkan bahwa sekarang ini adalah investasi tercepat dan terpendek dari berbagai pendekatan untuk Python 3.5.
Di Python 3.6, biasa dict menjadi terurut dan kompak. (Fitur ini berlaku untuk CPython dan Mount tapi mungkin tidak hadir dalam implementasi lainnya). Yang memberi kita baru cara tercepat deduping sementara tetap mempertahankan urutan:
>>> list(dict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']
Di Python 3.7, biasa dict dijamin untuk kedua memerintahkan seluruh implementasi. Jadi, terpendek dan tercepat solusinya adalah:
>>> list(dict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']
It's one-liner: daftar(set(source_list))
akan melakukan trik.
Set
adalah sesuatu yang dapat't mungkin memiliki duplikat.
Update: sebuah rangka melestarikan pendekatan dua jalur:
from collections import OrderedDict
OrderedDict((x, True) for x in source_list).keys()
Di sini kita menggunakan fakta bahwa OrderedDict
mengingat penyisipan urutan tombol, dan tidak berubah ketika nilai di kunci tertentu diperbarui. Kita menyisipkan Benar
sebagai nilai-nilai, tetapi kita bisa memasukkan apa-apa, nilai-nilai yang tidak digunakan. (set
bekerja banyak seperti dict
dengan mengabaikan nilai-nilai, juga.)
Untuk membuat daftar baru tetap mempertahankan urutan pertama unsur-unsur duplikat di L
newlist=[ii untuk n,ii dalam menghitung(L) jika ii tidak dalam L[:n]]
misalnya jika L=[1, 2, 2, 3, 4, 2, 4, 3, 5]
kemudian newlist
akan menjadi [1,2,3,4,5]
Ini cek setiap elemen baru telah muncul sebelumnya dalam daftar sebelum menambahkannya. Juga tidak perlu impor.
Seorang rekan telah mengirim jawaban yang diterima sebagai bagian dari kode nya kepada saya untuk codereview hari ini. Sementara saya pasti mengagumi keanggunan jawaban dalam pertanyaan, saya tidak senang dengan kinerja. Saya telah mencoba solusi ini (saya menggunakan set untuk mengurangi waktu pencarian)
def ordered_set(in_list):
out_list = []
added = set()
for val in in_list:
if not val in added:
out_list.append(val)
added.add(val)
return out_list
Untuk membandingkan efisiensi, saya menggunakan sampel acak dari 100 bilangan bulat - 62 yang unik
from random import randint
x = [randint(0,100) for _ in xrange(100)]
In [131]: len(set(x))
Out[131]: 62
Berikut ini adalah hasil pengukuran
In [129]: %timeit list(OrderedDict.fromkeys(x))
10000 loops, best of 3: 86.4 us per loop
In [130]: %timeit ordered_set(x)
100000 loops, best of 3: 15.1 us per loop
Nah, apa yang terjadi jika diatur dihapus dari solusi?
def ordered_set(inlist):
out_list = []
for val in inlist:
if not val in out_list:
out_list.append(val)
return out_list
Hasilnya tidak seburuk dengan OrderedDict, tapi masih lebih dari 3 kali dari solusi asli
In [136]: %timeit ordered_set(x)
10000 loops, best of 3: 52.6 us per loop
Ada juga solusi menggunakan Panda dan Numpy. Mereka berdua kembali numpy array sehingga anda harus menggunakan fungsi .kedaftar()
jika anda ingin daftar.
t=['a','a','b','b','b','c','c','c']
t2= ['c','c','b','b','b','a','a','a']
Menggunakan Panda fungsi unik()
:
import pandas as pd
pd.unique(t).tolist()
>>>['a','b','c']
pd.unique(t2).tolist()
>>>['c','b','a']
Menggunakan numpy fungsi unik()
.
import numpy as np
np.unique(t).tolist()
>>>['a','b','c']
np.unique(t2).tolist()
>>>['a','b','c']
Perhatikan bahwa numpy.unik() juga mengurutkan nilai-nilai. Jadi daftar t2
adalah kembali diurutkan. Jika anda ingin memiliki urutan yang diawetkan menggunakan jawaban ini:
_, idx = np.unique(t2, return_index=True)
t2[np.sort(idx)].tolist()
>>>['c','b','a']
Solusi ini tidak begitu elegan dibandingkan dengan yang lain, namun, dibandingkan dengan panda.unik(), numpy.unik() memungkinkan anda juga untuk memeriksa apakah bersarang array yang unik di sepanjang salah satu sumbu dipilih.
Aku punya dict dalam daftar saya, jadi saya tidak bisa menggunakan pendekatan di atas. Aku punya kesalahan:
TypeError: unhashable type:
Jadi jika anda peduli tentang order dan/atau beberapa item unhashable. Maka anda mungkin menemukan ini berguna:
def make_unique(original_list):
unique_list = []
[unique_list.append(obj) for obj in original_list if obj not in unique_list]
return unique_list
Beberapa mungkin mempertimbangkan daftar pemahaman dengan efek samping untuk tidak menjadi solusi yang baik. Berikut ini's alternatif:
def make_unique(original_list):
unique_list = []
map(lambda x: unique_list.append(x) if (x not in unique_list) else False, original_list)
return unique_list
Semua rangka melestarikan pendekatan I've dilihat di sini sejauh ini baik menggunakan naif perbandingan (dengan O(n^2) waktu-kompleksitas yang terbaik) atau berat-berat OrderedDicts
/set
+daftar
kombinasi yang terbatas untuk hashable input. Berikut ini adalah hash-independen O(nlogn) solusi:
Update ditambahkan kunci
argumen, dokumentasi dan Python 3 kompatibilitas.
# from functools import reduce <-- add this import on Python 3
def uniq(iterable, key=lambda x: x):
"""
Remove duplicates from an iterable. Preserves order.
:type iterable: Iterable[Ord => A]
:param iterable: an iterable of objects of any orderable type
:type key: Callable[A] -> (Ord => B)
:param key: optional argument; by default an item (A) is discarded
if another item (B), such that A == B, has already been encountered and taken.
If you provide a key, this condition changes to key(A) == key(B); the callable
must return orderable objects.
"""
# Enumerate the list to restore order lately; reduce the sorted list; restore order
def append_unique(acc, item):
return acc if key(acc[-1][1]) == key(item[1]) else acc.append(item) or acc
srt_enum = sorted(enumerate(iterable), key=lambda item: key(item[1]))
return [item[1] for item in sorted(reduce(append_unique, srt_enum, [srt_enum[0]]))]
Jika anda ingin mempertahankan urutan, dan tidak menggunakan modul-modul eksternal berikut ini adalah cara mudah untuk melakukan hal ini:
``python
t = [1, 9, 2, 3, 4, 5, 3, 6, 7, 5, 8, 9] daftar(dict.fromkeys(t)) [1, 9, 2, 3, 4, 5, 6, 7, 8] ``
Catatan: metode Ini mempertahankan urutan penampilan, jadi, seperti yang terlihat di atas, sembilan akan datang setelah satu karena ini adalah pertama kali muncul. Namun ini adalah hasil yang sama seperti yang anda akan dapatkan dengan melakukan
python dari koleksi import OrderedDict ulist=daftar(OrderedDict.fromkeys(l))
tapi itu jauh lebih pendek, dan berjalan lebih cepat.
Ini bekerja karena setiap kali fromkeys
fungsi mencoba untuk membuat kunci baru, jika nilai yang sudah ada itu hanya akan menimpa. Ini tidak akan mempengaruhi kamus pada semua namun, sebagai fromkeys
menciptakan kamus mana semua tombol memiliki value None
, sehingga secara efektif menghilangkan semua duplikat dengan cara ini.
Anda juga bisa melakukan ini:
>>> t = [1, 2, 3, 3, 2, 4, 5, 6]
>>> s = [x for i, x in enumerate(t) if i == t.index(x)]
>>> s
[1, 2, 3, 4, 5, 6]
Alasan bahwa karya-karya di atas adalah bahwa index
metode pengembalian hanya indeks pertama dari sebuah elemen. Duplikat unsur-unsur yang lebih tinggi memiliki indeks. Lihat di sini:
daftar.indeks(x[, start[, end]]) Return indeks berbasis-nol dalam daftar item pertama yang nilainya adalah x. Menimbulkan ValueError jika tidak ada item tersebut.
Mengurangi varian dengan memesan melestarikan:
Asumsikan bahwa kita memiliki daftar:
l = [5, 6, 6, 1, 1, 2, 2, 3, 4]
Mengurangi varian (unefficient):
>>> reduce(lambda r, v: v in r and r or r + [v], l, [])
[5, 6, 1, 2, 3, 4]
5 x lebih cepat tapi lebih canggih
>>> reduce(lambda r, v: v in r[1] and r or (r[0].append(v) or r[1].add(v)) or r, l, ([], set()))[0]
[5, 6, 1, 2, 3, 4]
Penjelasan:
default = (list(), set())
# user list to keep order
# use set to make lookup faster
def reducer(result, item):
if item not in result[1]:
result[0].append(item)
result[1].add(item)
return result
reduce(reducer, l, default)[0]
Anda dapat menggunakan fungsi berikut ini:
def rem_dupes(dup_list):
yooneeks = []
for elem in dup_list:
if elem not in yooneeks:
yooneeks.append(elem)
return yooneeks
Contoh:
my_list = ['this','is','a','list','with','dupicates','in', 'the', 'list']
Penggunaan:
rem_dupes(my_list)
['ini', 'adalah', 'a', 'daftar', 'dengan', 'dupicates', 'di', 'yang']
Pendekatan terbaik untuk menghapus duplikat dari daftar adalah menggunakan set() fungsi, tersedia dalam python, sekali lagi mengubah yang ditetapkan menjadi daftar
In [2]: some_list = ['a','a','v','v','v','c','c','d']
In [3]: list(set(some_list))
Out[3]: ['a', 'c', 'd', 'v']
Ada banyak jawaban yang lain menunjukkan cara yang berbeda untuk melakukan hal ini, tetapi mereka're semua operasi batch, dan beberapa dari mereka membuang urutan asli. Yang mungkin baik-baik saja tergantung pada apa yang anda perlu, tetapi jika anda ingin untuk iterate atas nilai-nilai dalam urutan dari contoh pertama dari masing-masing nilai, dan anda ingin menghapus duplikat on-the-fly terhadap semua sekaligus, anda bisa menggunakan generator ini:
def uniqify(iterable):
seen = set()
for item in iterable:
if item not in seen:
seen.add(item)
yield item
Hal ini mengembalikan sebuah generator/iterator, sehingga anda dapat menggunakannya di mana saja bahwa anda dapat menggunakan iterator.
for unique_item in uniqify([1, 2, 3, 4, 3, 2, 4, 5, 6, 7, 6, 8, 8]):
print(unique_item, end=' ')
print()
Output:
1 2 3 4 5 6 7 8
Jika anda ingin melakukan daftar
, anda dapat melakukan ini:
unique_list = list(uniqify([1, 2, 3, 4, 3, 2, 4, 5, 6, 7, 6, 8, 8]))
print(unique_list)
Output:
[1, 2, 3, 4, 5, 6, 7, 8]