Menghapus duplikat dalam daftar


997

Cukup banyak saya perlu menulis sebuah program untuk memeriksa apakah daftar memiliki duplikat dan jika itu menghapusnya dan mengembalikan daftar baru dengan barang-barang yang tidak digandakan / dihapus. Inilah yang saya miliki tetapi jujur ​​saya tidak tahu harus berbuat apa.

def remove_duplicates():
    t = ['a', 'b', 'c', 'd']
    t2 = ['a', 'c', 'd']
    for t in t2:
        t.append(t.remove())
    return t

22
Deskripsi Anda mengatakan Anda memeriksa "daftar" untuk duplikat, tetapi kode Anda memeriksa dua daftar.
Brendan Long


* menggunakan set: daftar (set (ELEMENTS_LIST)) * menggunakan kamus: daftar (dict.fromkeys (ELEMENTS_LIST))
Shayan Amani

Jawaban:


1642

Pendekatan umum untuk mendapatkan koleksi barang yang unik adalah menggunakan a set. Set unordered koleksi yang berbeda objek. Untuk membuat satu set dari setiap iterable, Anda bisa meneruskannya ke set()fungsi bawaan. Jika nanti Anda membutuhkan daftar nyata lagi, Anda dapat meneruskan set ke list()fungsi yang sama.

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 hasil contoh, urutan asli tidak dipertahankan . Seperti disebutkan di atas, set sendiri adalah koleksi yang tidak terurut, sehingga urutannya hilang. Saat mengonversi satu set kembali ke daftar, perintah sewenang-wenang dibuat.

Mempertahankan ketertiban

Jika pesanan penting bagi Anda, maka Anda harus menggunakan mekanisme yang berbeda. Solusi yang sangat umum untuk ini adalah dengan mengandalkan OrderedDictuntuk menjaga urutan kunci selama penyisipan:

>>> from collections import OrderedDict
>>> list(OrderedDict.fromkeys(t))
[1, 2, 3, 5, 6, 7, 8]

Dimulai dengan Python 3.7 , kamus internal dijamin untuk menjaga urutan penyisipan juga, jadi Anda juga dapat menggunakannya secara langsung jika Anda menggunakan Python 3.7 atau lebih baru (atau CPython 3.6):

>>> list(dict.fromkeys(t))
[1, 2, 3, 5, 6, 7, 8]

Perhatikan bahwa ini mungkin memiliki overhead menciptakan kamus pertama, dan kemudian membuat daftar darinya. Jika Anda tidak benar-benar perlu mempertahankan pesanan, Anda sering lebih baik menggunakan satu set, terutama karena itu memberi Anda lebih banyak operasi untuk dikerjakan. Lihat pertanyaan ini untuk detail lebih lanjut dan cara-cara alternatif untuk mempertahankan pesanan saat menghapus duplikat.


Akhirnya catatan bahwa baik setserta OrderedDict/ dictsolusi memerlukan item Anda untuk menjadi hashable . Ini biasanya berarti bahwa mereka harus abadi. Jika Anda harus berurusan dengan item yang tidak hashable (misalnya objek daftar), maka Anda harus menggunakan pendekatan lambat di mana Anda pada dasarnya harus membandingkan setiap item dengan setiap item lainnya dalam loop bersarang.


4
Ini tidak berfungsi untuk elemen daftar yang tidak dapat dihancurkan (mis. Daftar daftar)
KNejad

3
@KNejad Itulah yang dinyatakan paragraf terakhir.
colek

Oh oops. Seharusnya membaca semuanya. Apa yang akhirnya saya lakukan adalah menggunakan tuple bukan daftar sehingga pendekatan ini masih bisa bekerja.
KNejad

tambahkan ini sebagai contoh, t = [3, 2, 1, 1, 2, 5, 6, 7, 8], menunjukkan perbedaannya dengan jelas!
sailfish009

"... overhead membuat kamus dulu ... Jika kamu tidak benar-benar perlu mempertahankan pesanan, kamu lebih baik menggunakan satu set." - Saya membuat profil ini karena saya ingin tahu apakah itu benar. Pengaturan waktu saya menunjukkan bahwa memang set sedikit lebih cepat: 1,12 μs per loop (set) vs 1,53 μs per loop (dict) lebih dari 1M loop dengan perbedaan waktu absolut sekitar 4s lebih dari iterasi 1M. Jadi, jika Anda melakukan ini dalam lingkaran batin yang ketat Anda mungkin peduli, jika tidak, mungkin tidak.
millerdev

414

Dalam Python 2.7 , cara baru untuk menghapus duplikat dari iterable sambil menjaganya dalam urutan asli adalah:

>>> from collections import OrderedDict
>>> list(OrderedDict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']

Dalam Python 3.5 , OrderedDict memiliki implementasi C. Pengaturan waktu saya menunjukkan bahwa ini sekarang adalah yang tercepat dan terpendek dari berbagai pendekatan untuk Python 3.5.

Dalam Python 3.6 , perintah reguler menjadi teratur dan kompak. (Fitur ini berlaku untuk CPython dan PyPy tetapi mungkin tidak ada dalam implementasi lain). Itu memberi kami cara deduksi tercepat baru sambil mempertahankan pesanan:

>>> list(dict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']

Dalam Python 3.7 , dikt reguler dijamin untuk keduanya dipesan di semua implementasi. Jadi, solusi terpendek dan tercepat adalah:

>>> list(dict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']

10
Saya pikir ini adalah satu-satunya cara untuk menjaga barang tetap teratur.
Herberth Amaral


5
@MartijnPieters Memperbaiki: Saya pikir ini adalah satu-satunya cara sederhana untuk menjaga barang tetap teratur.
Herberth Amaral

12
Untuk ini juga, isi dari daftar asli harus dapat hashable
Davide

Seperti @Davide sebutkan, daftar asli harus di hashable. Ini berarti, bahwa ini tidak berfungsi untuk daftar kamus. TypeError: unhashable type: 'dictlist'
CraZ

187

Ini satu-baris: list(set(source_list))akan melakukan trik.

A setadalah sesuatu yang tidak mungkin memiliki duplikat.

Pembaruan: pendekatan pelestarian pesanan adalah dua baris:

from collections import OrderedDict
OrderedDict((x, True) for x in source_list).keys()

Di sini kita menggunakan fakta yang OrderedDictmengingat urutan penyisipan kunci, dan tidak mengubahnya ketika nilai pada kunci tertentu diperbarui. Kami menyisipkan Truesebagai nilai, tetapi kami dapat menyisipkan apa pun, nilai tidak digunakan. ( setbekerja sangat mirip dictdengan nilai yang diabaikan juga.)


5
Ini hanya berfungsi jika source_listhashable.
Adrian Keister

@AdrianKeister: Ini benar. Ada objek yang memiliki semantik kesetaraan yang masuk akal tetapi tidak dapat hashable, misalnya daftar. OTOH jika kita tidak dapat memiliki jalan pintas seperti hastable, kita berakhir dengan algoritma kuadratik yang hanya membandingkan setiap elemen dengan semua elemen unik yang saat ini dikenal. Ini bisa sepenuhnya OK untuk input pendek, terutama dengan banyak duplikat.
9000

Tepat, tepatnya. Saya pikir jawaban Anda akan berkualitas lebih tinggi jika Anda mempertimbangkan kasus penggunaan yang sangat umum ini.
Adrian Keister

95
>>> t = [1, 2, 3, 1, 2, 5, 6, 7, 8]
>>> t
[1, 2, 3, 1, 2, 5, 6, 7, 8]
>>> s = []
>>> for i in t:
       if i not in s:
          s.append(i)
>>> s
[1, 2, 3, 5, 6, 7, 8]

33
Perhatikan bahwa metode ini bekerja dalam waktu O (n ^ 2) dan karena itu sangat lambat pada daftar besar.
dotancohen

@Chris_Rands: Tidak yakin frozensetberfungsi dengan konten yang tidak dapat diacak. Saya masih mendapatkan kesalahan tidak hash saat menggunakan frozenset.
Adrian Keister

85

Jika Anda tidak peduli dengan pesanannya, lakukan saja ini:

def remove_duplicates(l):
    return list(set(l))

A setdijamin tidak memiliki duplikat.


3
Tidak berfungsi kecuali lhashable.
Adrian Keister

41

Untuk membuat daftar baru mempertahankan urutan elemen pertama duplikat di L

newlist=[ii for n,ii in enumerate(L) if ii not in L[:n]]

misalnya if L=[1, 2, 2, 3, 4, 2, 4, 3, 5]maka newlistakan[1,2,3,4,5]

Ini memeriksa setiap elemen baru belum muncul sebelumnya dalam daftar sebelum menambahkannya. Juga tidak perlu impor.


3
Ini memiliki kompleksitas waktu O (n ^ 2) . Jawaban dengan setdan OrderedDictmungkin memiliki kompleksitas waktu diamortisasi yang lebih rendah.
blubberdiblub

Saya menggunakan dalam kode saya solusi ini dan bekerja dengan baik tetapi saya pikir ini memakan waktu
Gerasimos Ragavanis

@blubberdiblub dapatkah Anda menjelaskan mekanisme efisien kode apa yang ada di set dan OrderedDict yang dapat membuatnya lebih sedikit memakan waktu? (tidak termasuk biaya overhead untuk memuatnya)
ilias iliadis

@iliasiliadis Implementasi biasa set dan dict penggunaan hash atau (beberapa bentuk seimbang) pohon. Anda harus mempertimbangkan untuk membangun set atau dict dan mencari di dalamnya (beberapa kali), tetapi kompleksitasnya diamortisasi biasanya masih lebih rendah dari O (n ^ 2) . "Amortisasi" secara sederhana berarti rata-rata (mereka dapat memiliki kasus terburuk dengan kompleksitas lebih tinggi daripada rata-rata kasus) Ini hanya relevan ketika Anda memiliki sejumlah besar item.
blubberdiblub

25

Seorang kolega telah mengirim jawaban yang diterima sebagai bagian dari kodenya kepada saya untuk codereview hari ini. Meskipun saya pasti mengagumi keanggunan jawaban yang dipermasalahkan, saya tidak senang dengan penampilannya. 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 100 bilangan bulat - 62 unik

from random import randint
x = [randint(0,100) for _ in xrange(100)]

In [131]: len(set(x))
Out[131]: 62

Berikut adalah hasil pengukurannya

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 set 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 , tetapi masih lebih dari 3 kali dari solusi asli

In [136]: %timeit ordered_set(x)
10000 loops, best of 3: 52.6 us per loop

Bagus menggunakan set lookup cepat untuk mempercepat perbandingan loop. Jika urutan tidak penting, daftar (set (x)) masih 6x lebih cepat dari ini
Joop

@Joop, itu adalah pertanyaan pertama saya untuk rekan saya - pesanan itu penting; jika tidak, itu akan menjadi masalah sepele
gunung berapi

versi yang dioptimalkan dari kumpulan yang dipesan, untuk siapa saja yang tertarik def unique(iterable)::; seen = set(); seen_add = seen.add; return [item for item in iterable if not item in seen and not seen_add(item)]
DrD

25

Ada juga solusi menggunakan Pandas dan Numpy. Keduanya mengembalikan array numpy sehingga Anda harus menggunakan fungsi .tolist()jika Anda ingin daftar.

t=['a','a','b','b','b','c','c','c']
t2= ['c','c','b','b','b','a','a','a']

Solusi panda

Menggunakan fungsi Pandas unique():

import pandas as pd
pd.unique(t).tolist()
>>>['a','b','c']
pd.unique(t2).tolist()
>>>['c','b','a']

Solusi numpy

Menggunakan fungsi numpy unique().

import numpy as np
np.unique(t).tolist()
>>>['a','b','c']
np.unique(t2).tolist()
>>>['a','b','c']

Perhatikan bahwa numpy.unique () juga mengurutkan nilai . Jadi daftar t2dikembalikan disortir. Jika Anda ingin agar pesanan tetap digunakan seperti dalam jawaban ini :

_, idx = np.unique(t2, return_index=True)
t2[np.sort(idx)].tolist()
>>>['c','b','a']

Solusinya tidak begitu elegan dibandingkan dengan yang lain, namun, dibandingkan dengan panda.unique (), numpy.unique () memungkinkan Anda juga untuk memeriksa apakah array bersarang unik di sepanjang satu sumbu yang dipilih.


Ini akan mengubah daftar menjadi array numpy yang berantakan dan tidak akan berfungsi untuk string.
user227666

1
@ user227666 terima kasih atas ulasan Anda tapi itu tidak benar itu berfungsi bahkan dengan string dan Anda dapat menambahkan .tolist jika Anda ingin mendapatkan daftar ...
GM

1
Saya pikir ini seperti mencoba membunuh lebah dengan palu godam. Bekerja tentu! Tetapi, mengimpor perpustakaan untuk tujuan ini mungkin sedikit berlebihan, bukan?
Debosmit Ray

@DebosmitRay dapat berguna jika Anda bekerja di Ilmu Data di mana biasanya Anda bekerja dengan numpy dan berkali-kali Anda perlu bekerja dengan numpy array.
GM

jawaban terbaik di 2020 @DebosmitRay saya harap Anda berubah pikiran dan menggunakan numpy / panda setiap kali Anda bisa
Egos

21

Cara lain untuk melakukan:

>>> seq = [1,2,3,'a', 'a', 1,2]
>> dict.fromkeys(seq).keys()
['a', 1, 2, 3]

1
Perhatikan bahwa dalam versi Python modern (2,7+ saya pikir, tapi saya tidak ingat pasti), keys()mengembalikan objek tampilan kamus, bukan daftar.
Dustin Wyatt

16

Sederhana dan mudah:

myList = [1, 2, 3, 1, 2, 5, 6, 7, 8]
cleanlist = []
[cleanlist.append(x) for x in myList if x not in cleanlist]

Keluaran:

>>> cleanlist 
[1, 2, 3, 5, 6, 7, 8]

5
kompleksitas kuadrat tetap - inadalah operasi O (n) dan Anda cleanlistakan memiliki paling banyak nangka => kasus terburuk ~ O (n ^ 2)
jermenkoo

6
daftar pemahaman tidak boleh digunakan untuk efek samping.
Jean-François Fabre

13

Dalam jawaban ini, akan ada dua bagian: Dua solusi unik, dan grafik kecepatan untuk solusi spesifik.

Menghapus Item Duplikat

Sebagian besar jawaban ini hanya menghapus item duplikat yang dapat hashable , tetapi pertanyaan ini tidak menyiratkan itu tidak hanya membutuhkan item hashable , artinya saya akan menawarkan beberapa solusi yang tidak memerlukan item hashable .

collections.Counter adalah alat yang ampuh di perpustakaan standar yang bisa menjadi sempurna untuk ini. Hanya ada satu solusi lain yang bahkan memiliki Counter di dalamnya. Namun, solusi itu juga terbatas pada kunci hashable .

Untuk memperbolehkan kunci yang tidak dapat pecah di Counter, saya membuat kelas Container, yang akan mencoba untuk mendapatkan fungsi hash default objek, tetapi jika gagal, ia akan mencoba fungsi identitasnya. Ini juga mendefinisikan metode eq dan hash . Ini harus cukup untuk memungkinkan barang yang tidak dapat dihancurkan dalam solusi kami. Objek yang tidak bisa pecah akan diperlakukan seolah-olah objek tersebut dapat hashable. Namun, fungsi hash ini menggunakan identitas untuk objek-objek yang tidak bisa didapati, yang berarti dua objek yang sama-sama tidak bisa dilepas tidak akan berfungsi. Saya sarankan Anda menimpa ini, dan mengubahnya untuk menggunakan hash dari jenis yang bisa berubah-ubah (seperti menggunakan hash(tuple(my_list))jika my_listadalah daftar).

Saya juga membuat dua solusi. Solusi lain yang menjaga urutan barang, menggunakan subclass dari OrderedDict dan Counter yang dinamai 'OrderedCounter'. Sekarang, inilah fungsinya:

from collections import OrderedDict, Counter

class Container:
    def __init__(self, obj):
        self.obj = obj
    def __eq__(self, obj):
        return self.obj == obj
    def __hash__(self):
        try:
            return hash(self.obj)
        except:
            return id(self.obj)

class OrderedCounter(Counter, OrderedDict):
     'Counter that remembers the order elements are first encountered'

     def __repr__(self):
         return '%s(%r)' % (self.__class__.__name__, OrderedDict(self))

     def __reduce__(self):
         return self.__class__, (OrderedDict(self),)

def remd(sequence):
    cnt = Counter()
    for x in sequence:
        cnt[Container(x)] += 1
    return [item.obj for item in cnt]

def oremd(sequence):
    cnt = OrderedCounter()
    for x in sequence:
        cnt[Container(x)] += 1
    return [item.obj for item in cnt]

remd adalah penyortiran yang tidak dipesan, oremd adalah penyortiran yang dipesan. Anda dapat dengan jelas mengetahui mana yang lebih cepat, tetapi saya akan menjelaskannya. Penyortiran yang tidak teratur sedikit lebih cepat. Itu menyimpan lebih sedikit data, karena tidak perlu dipesan.

Sekarang, saya juga ingin menunjukkan perbandingan kecepatan dari setiap jawaban. Jadi, saya akan melakukannya sekarang.

Fungsi mana yang tercepat?

Untuk menghapus duplikat, saya mengumpulkan 10 fungsi dari beberapa jawaban. Saya menghitung kecepatan setiap fungsi dan memasukkannya ke dalam grafik menggunakan matplotlib.pyplot .

Saya membagi ini menjadi tiga putaran grafik. Sebuah hashable adalah objek apa pun yang dapat hash, sebuah hashable adalah objek yang tidak dapat hash. Urutan berurutan adalah urutan yang mempertahankan pesanan, urutan yang tidak berurutan tidak mempertahankan pesanan. Sekarang, inilah beberapa istilah lagi:

Unordered Hashable adalah untuk metode apa pun yang menghapus duplikat, yang tidak selalu harus menjaga ketertiban. Itu tidak harus bekerja untuk orang yang tidak terluka, tetapi itu bisa.

Memesan Hashable adalah untuk metode apa pun yang menjaga urutan item dalam daftar, tetapi itu tidak harus bekerja untuk yang tak tergoyahkan, tetapi bisa.

Ordered Unhashable adalah metode apa pun yang menjaga urutan item dalam daftar, dan bekerja untuk unhashables.

Pada sumbu y adalah jumlah detik yang dibutuhkan.

Pada sumbu x adalah angka fungsi diterapkan.

Kami membuat urutan untuk hashable yang tidak berurutan dan memesan hashable dengan pemahaman sebagai berikut: [list(range(x)) + list(range(x)) for x in range(0, 1000, 10)]

Untuk pesanan yang belum dipesan: [[list(range(y)) + list(range(y)) for y in range(x)] for x in range(0, 1000, 10)]

Perhatikan ada 'langkah' dalam rentang karena tanpa itu, ini akan memakan waktu 10x lebih lama. Juga karena menurut pendapat pribadi saya, saya pikir itu mungkin terlihat sedikit lebih mudah dibaca.

Juga perhatikan kunci pada legenda adalah apa yang saya coba tebak sebagai bagian terpenting dari fungsi. Adapun fungsi apa yang paling buruk atau terbaik? Grafik berbicara sendiri.

Dengan itu diselesaikan, di sini adalah grafik.

Hashables yang Tidak Diatur

masukkan deskripsi gambar di sini (Diperbesar) masukkan deskripsi gambar di sini

Hashables Dipesan

masukkan deskripsi gambar di sini (Diperbesar) masukkan deskripsi gambar di sini

Tidak Terperintahkan Dipesan

masukkan deskripsi gambar di sini (Diperbesar) masukkan deskripsi gambar di sini


11

Saya punya dict dalam daftar saya, jadi saya tidak bisa menggunakan pendekatan di atas. Saya mendapat kesalahan:

TypeError: unhashable type:

Jadi, jika Anda peduli dengan pesanan dan / atau beberapa item tidak dapat rusak . 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 orang mungkin mempertimbangkan pemahaman daftar dengan efek samping untuk tidak menjadi solusi yang baik. Inilah alternatifnya:

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

6
mapdengan efek samping bahkan lebih menyesatkan daripada listcomp dengan efek samping. Juga, lambda x: unique_list.append(x)ini hanya cara yang lebih rumit dan lebih lambat untuk dilewati unique_list.append.
abarnert

Cara yang sangat berguna untuk menambahkan elemen hanya dalam satu baris, terima kasih!
ZLNK

2
@ZLNK tolong, jangan pernah gunakan itu. Selain jelek secara konseptual, itu juga sangat tidak efisien, karena Anda benar-benar membuat daftar yang berpotensi besar dan membuangnya hanya untuk melakukan iterasi dasar.
Eli Korvigo

10

Semua pendekatan pelestarian pesanan yang saya lihat di sini sejauh ini baik menggunakan perbandingan naif (dengan O (n ^ 2) kompleksitas waktu terbaik) atau kombinasi berat OrderedDicts/ set+ listyang terbatas pada input hashable. Berikut ini adalah solusi O (nlogn) bebas hash:

Pembaruan menambahkan keyargumen, dokumentasi dan kompatibilitas Python 3.

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

Namun, solusi ini membutuhkan elemen yang dapat dipesan. Saya akan menggunakannya uniquify daftar daftar saya: itu menyakitkan untuk tuple()daftar dan hash mereka. | | | | - Secara umum, proses hash membutuhkan waktu yang proporsional dengan ukuran seluruh data, sementara solusi ini membutuhkan waktu O (nlog (n)), tergantung hanya pada panjang daftar.
loxaxs

Saya berpikir bahwa pendekatan berbasis set sama-sama murah (O (n log n)), atau lebih murah, daripada menyortir + deteksi uniques. (Pendekatan ini akan memparalelkan jauh lebih baik.) Ini juga tidak persis mempertahankan urutan awal, tetapi memberikan urutan yang dapat diprediksi.
9000

@ 9000 Itu benar. Saya tidak pernah menyebutkan kompleksitas waktu dari pendekatan berbasis tabel hash, yang jelas O (n). Di sini Anda dapat menemukan banyak jawaban dengan menggabungkan hash-tables. Mereka tidak universal, karena mereka membutuhkan objek yang dapat hashable. Selain itu, mereka jauh lebih banyak menggunakan memori.
Eli Korvigo

Butuh waktu untuk membaca dan memahami jawaban ini. Apakah ada gunanya penghitungan saat Anda tidak menggunakan indeks? The reduce() sudah bekerja pada koleksi diurutkan srt_enum, mengapa Anda menerapkan sortedlagi?
Brayoni

@Brayoni jenis pertama ada untuk mengelompokkan nilai yang sama, jenis kedua ada untuk mengembalikan urutan awal. Penghitungan diperlukan untuk melacak urutan relatif asli.
Eli Korvigo

9

Jika Anda ingin mempertahankan pesanan, dan tidak menggunakan modul eksternal apa pun di sini adalah cara mudah untuk melakukan ini:

>>> t = [1, 9, 2, 3, 4, 5, 3, 6, 7, 5, 8, 9]
>>> list(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 muncul setelah satu karena itu adalah pertama kalinya itu muncul. Namun, ini adalah hasil yang sama seperti yang Anda dapatkan dengan melakukan

from collections import OrderedDict
ulist=list(OrderedDict.fromkeys(l))

tetapi jauh lebih pendek, dan berjalan lebih cepat.

Ini berfungsi karena setiap kali fromkeysfungsi mencoba membuat kunci baru, jika nilainya sudah ada, ia hanya akan menimpanya. Namun ini tidak akan mempengaruhi kamus sama sekali, seperti fromkeysmembuat kamus di mana semua kunci memiliki nilai None, sehingga secara efektif menghilangkan semua duplikat dengan cara ini.


Coba juga di sini
vineeshvs

8

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 di atas berfungsi adalah bahwa indexmetode mengembalikan hanya indeks pertama dari suatu elemen. Elemen duplikat memiliki indeks lebih tinggi. Lihat di sini :

list.index (x [, mulai [, akhir]])
Mengembalikan indeks berbasis nol dalam daftar item pertama yang nilainya x. Meningkatkan ValueError jika tidak ada item seperti itu.


Ini sangat tidak efisien. list.indexadalah operasi linear-waktu, membuat solusi Anda kuadratik.
Eli Korvigo

Kamu benar. Tetapi saya juga percaya itu cukup jelas solusinya dimaksudkan untuk menjadi satu liner yang mempertahankan pesanan. Semua yang lain sudah ada di sini.
Atonal

7

Coba gunakan set:

import sets
t = sets.Set(['a', 'b', 'c', 'd'])
t1 = sets.Set(['a', 'b', 'c'])

print t | t1
print t - t1

7

Kurangi varian dengan penyimpanan pesanan:

Anggaplah kita memiliki daftar:

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

Kurangi varian (tidak efisien):

>>> reduce(lambda r, v: v in r and r or r + [v], l, [])
[5, 6, 1, 2, 3, 4]

5 x lebih cepat tetapi 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]

7

Pendekatan terbaik untuk menghapus duplikat dari daftar menggunakan fungsi set () , tersedia dalam python, sekali lagi mengubah set itu ke dalam 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']

@MeetZaveri senang.!
Anurag Misra

Membuat instance daftar dan set baru tidak gratis. Apa yang terjadi jika kita melakukan ini berkali-kali secara berurutan (mis. Dalam lingkaran yang sangat ketat), dan daftarnya sangat kecil?
Z4-tier

6

Anda dapat menggunakan fungsi berikut:

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

Pemakaian:

rem_dupes(my_list)

['this', 'is', 'a', 'list', 'with', 'dupicates', 'in', 'the']


5

Ada banyak jawaban lain yang menyarankan berbagai cara untuk melakukan ini, tetapi semuanya adalah operasi batch, dan beberapa dari mereka membuang urutan aslinya. Itu mungkin baik-baik saja tergantung pada apa yang Anda butuhkan, tetapi jika Anda ingin beralih pada nilai-nilai dalam urutan contoh pertama dari setiap nilai, dan Anda ingin menghapus duplikat on-the-fly versus 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

Ini mengembalikan generator / iterator, sehingga Anda dapat menggunakannya di mana saja 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()

Keluaran:

1 2 3 4 5 6 7 8

Jika Anda menginginkannya list, Anda dapat melakukan ini:

unique_list = list(uniqify([1, 2, 3, 4, 3, 2, 4, 5, 6, 7, 6, 8, 8]))

print(unique_list)

Keluaran:

[1, 2, 3, 4, 5, 6, 7, 8]

seen = set(iterable); for item in seen: yield itemhampir pasti lebih cepat. (Saya belum mencoba kasus khusus ini, tetapi itu akan menjadi dugaan saya.)
dylnmc

2
@ Dnmnmc, itu operasi batch, dan itu juga kehilangan pemesanan. Jawaban saya secara khusus dimaksudkan untuk on-the-fly dan sesuai urutan kejadian pertama. :)
Cyphase

5

Tanpa menggunakan set

data=[1, 2, 3, 1, 2, 5, 6, 7, 8]
uni_data=[]
for dat in data:
    if dat not in uni_data:
        uni_data.append(dat)

print(uni_data) 

5

Anda dapat menggunakan setuntuk menghapus duplikat:

mylist = list(set(mylist))

Tetapi perhatikan hasilnya akan tidak tertata. Jika itu masalah:

mylist.sort()

1
Anda bisa melakukannya: mylist = diurutkan (list (set (mylist)))
Erik Campobadal

5

Satu lagi pendekatan yang lebih baik,

import pandas as pd

myList = [1, 2, 3, 1, 2, 5, 6, 7, 8]
cleanList = pd.Series(myList).drop_duplicates().tolist()
print(cleanList)

#> [1, 2, 3, 5, 6, 7, 8]

dan pesanan tetap dipertahankan.


Meskipun ini mungkin bekerja dengan baik, menggunakan perpustakaan yang berat seperti panda untuk tujuan ini sepertinya berlebihan.
Glutexo

4

Yang ini peduli dengan pesanan tanpa terlalu banyak kesulitan (OrderdDict & lainnya). Mungkin bukan cara yang paling Pythonic, atau cara terpendek, tetapi melakukan trik:

def remove_duplicates(list):
    ''' Removes duplicate items from a list '''
    singles_list = []
    for element in list:
        if element not in singles_list:
            singles_list.append(element)
    return singles_list

1. Anda tidak boleh membayangi nama builtin (setidaknya, sepenting list); 2. Metode Anda berskala sangat buruk: kuadratik dalam jumlah elemen di list.
Eli Korvigo

1. Benar, tetapi ini adalah contoh; 2. Benar, dan itulah alasan mengapa saya menawarkannya. Semua solusi yang diposting di sini memiliki pro dan kontra. Beberapa pengorbanan kesederhanaan atau ketertiban, skalabilitas pengorbanan tambang.
cgf

ini adalah algoritma "Shlemiel the pelukis" ...
Z4-tier

4

kode di bawah ini mudah untuk menghapus duplikat dalam daftar

def remove_duplicates(x):
    a = []
    for i in x:
        if i not in a:
            a.append(i)
    return a

print remove_duplicates([1,2,2,3,3,4])

mengembalikan [1,2,3,4]


2
Jika Anda tidak peduli tentang pesanan, maka ini akan memakan waktu lebih lama. list(set(..))(lebih dari 1 juta pass) akan mengalahkan solusi ini sekitar 10 detik penuh - sedangkan pendekatan ini membutuhkan waktu sekitar 12 detik, list(set(..))hanya membutuhkan waktu sekitar 2 detik!
dylnmc

@dylnmc ini juga merupakan duplikat dari jawaban yang
Eli Korvigo

4

Inilah solusi pythonic tercepat yang dikirimkan ke orang lain yang tercantum dalam balasan.

Menggunakan detail implementasi evaluasi hubung singkat memungkinkan untuk menggunakan pemahaman daftar, yang cukup cepat. visited.add(item)selalu kembali Nonesebagai hasilnya, yang dievaluasi sebagai False, jadi sisi kananor akan selalu menjadi hasil dari ungkapan seperti itu.

Waktunya sendiri

def deduplicate(sequence):
    visited = set()
    adder = visited.add  # get rid of qualification overhead
    out = [adder(item) or item for item in sequence if item not in visited]
    return out

4

Menggunakan set :

a = [0,1,2,3,4,3,3,4]
a = list(set(a))
print a

Menggunakan unik :

import numpy as np
a = [0,1,2,3,4,3,3,4]
a = np.unique(a).tolist()
print a

4

Sayangnya. Sebagian besar jawaban di sini tidak mempertahankan pesanan atau terlalu lama. Berikut ini adalah jawaban sederhana, untuk menjaga agar.

s = [1,2,3,4,5,2,5,6,7,1,3,9,3,5]
x=[]

[x.append(i) for i in s if i not in x]
print(x)

Ini akan memberi Anda x dengan duplikat yang dihapus tetapi tetap mempertahankan pesanan.


3

Cara yang sangat sederhana dalam Python 3:

>>> n = [1, 2, 3, 4, 1, 1]
>>> n
[1, 2, 3, 4, 1, 1]
>>> m = sorted(list(set(n)))
>>> m
[1, 2, 3, 4]

2
sorted(list(...))redundan ( sortedsudah secara implisit mengonversi argumennya menjadi yang baru list, mengurutkannya, lalu mengembalikan yang baru list, jadi menggunakan keduanya berarti membuat sementara yang tidak perlu list). Gunakan hanya listjika hasilnya tidak perlu disortir, gunakan hanya sortedjika hasilnya perlu disortir.
ShadowRanger

3

Keajaiban jenis Python Built-in

Dalam python, sangat mudah untuk memproses kasus rumit seperti ini dan hanya dengan tipe bawaan python.

Mari saya tunjukkan caranya!

Metode 1: Kasus Umum

Caranya ( 1 kode baris ) untuk menghapus elemen yang digandakan dalam daftar dan tetap menjaga urutan penyortiran

line = [1, 2, 3, 1, 2, 5, 6, 7, 8]
new_line = sorted(set(line), key=line.index) # remove duplicated element
print(new_line)

Anda akan mendapatkan hasilnya

[1, 2, 3, 5, 6, 7, 8]

Metode 2: Kasus Khusus

TypeError: unhashable type: 'list'

Kasing khusus untuk memproses yang tidak dapat pecah ( 3 kode baris )

line=[['16.4966155686595', '-27.59776154691', '52.3786295521147']
,['16.4966155686595', '-27.59776154691', '52.3786295521147']
,['17.6508629295574', '-27.143305738671', '47.534955022564']
,['17.6508629295574', '-27.143305738671', '47.534955022564']
,['18.8051102904552', '-26.688849930432', '42.6912804930134']
,['18.8051102904552', '-26.688849930432', '42.6912804930134']
,['19.5504702331098', '-26.205884452727', '37.7709192714727']
,['19.5504702331098', '-26.205884452727', '37.7709192714727']
,['20.2929416861422', '-25.722717575124', '32.8500163147157']
,['20.2929416861422', '-25.722717575124', '32.8500163147157']]

tuple_line = [tuple(pt) for pt in line] # convert list of list into list of tuple
tuple_new_line = sorted(set(tuple_line),key=tuple_line.index) # remove duplicated element
new_line = [list(t) for t in tuple_new_line] # convert list of tuple into list of list

print (new_line)

Anda akan mendapatkan hasilnya:

[
  ['16.4966155686595', '-27.59776154691', '52.3786295521147'], 
  ['17.6508629295574', '-27.143305738671', '47.534955022564'], 
  ['18.8051102904552', '-26.688849930432', '42.6912804930134'], 
  ['19.5504702331098', '-26.205884452727', '37.7709192714727'], 
  ['20.2929416861422', '-25.722717575124', '32.8500163147157']
]

Karena tuple hashable dan Anda dapat mengkonversi data antara daftar dan tuple dengan mudah

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.