Listelerde yinelenenleri kaldırma


995

Hemen hemen bir liste herhangi bir yinelenen olup olmadığını kontrol etmek için bir program yazmak gerekir ve eğer o onları kaldırır ve çoğaltılmamış / kaldırılmayan öğeleri ile yeni bir liste döndürür. Sahip olduğum şey bu ama dürüst olmak gerekirse ne yapacağımı bilmiyorum.

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

22
Açıklamanızda, kopyalar için "listeyi" kontrol ettiğiniz belirtiliyor, ancak kodunuz iki listeyi kontrol ediyor.
Brendan Long


* set: list kullanarak (set (ELEMENTS_LIST)) * sözlük kullanarak: list (dict.fromkeys (ELEMENTS_LIST))
Shayan Amani

Yanıtlar:


1641

Eşsiz bir ürün koleksiyonu elde etmek için ortak yaklaşım a set. Kümeler farklı nesnelerin sırasız koleksiyonlarıdır . Herhangi bir yinelemeden bir set oluşturmak için basitçe yerleşik işleve geçirebilirsiniz . Daha sonra tekrar gerçek bir listeye ihtiyacınız varsa, seti benzer şekilde işleve geçirebilirsiniz .set()list()

Aşağıdaki örnek, yapmaya çalıştığınız her şeyi kapsamalıdır:

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

Örnek sonuçtan da görebileceğiniz gibi , orijinal sipariş korunmaz . Yukarıda belirtildiği gibi, kümelerin kendileri sıralanmamış koleksiyonlardır, bu nedenle sipariş kaybolur. Bir seti tekrar listeye dönüştürürken, rasgele bir sipariş oluşturulur.

Siparişi korumak

Sipariş sizin için önemliyse, farklı bir mekanizma kullanmanız gerekecektir. Bunun için çok yaygın bir çözüm, OrderedDictekleme sırasında anahtarların sırasını korumaya güvenmektir :

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

Python 3.7'den başlayarak , dahili sözlüğün ekleme sırasını da koruyacağı garanti edilir, bu nedenle doğrudan Python 3.7 veya sonraki bir sürümde (veya CPython 3.6) kullanıyorsanız da bunu kullanabilirsiniz:

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

Bunun önce bir sözlük oluşturma ve ardından bir liste oluşturma yükü olabileceğini unutmayın. Siparişi gerçekten korumanıza gerek yoksa, genellikle bir set kullanmaktan daha iyi olursunuz, özellikle de çalışmak için çok daha fazla işlem verir. Kopyaları kaldırırken daha fazla ayrıntı ve sırayı korumanın alternatif yolları için bu soruya göz atın .


Nihayet de o notu setyanı sıra OrderedDict/ dictçözümleri öğeleri gerektiren olmak hashable . Bu genellikle değişmez olmaları gerektiği anlamına gelir. Yıkanamayan öğelerle (örneğin, liste nesneleri) ilgilenmeniz gerekiyorsa, temel olarak her öğeyi iç içe bir döngüdeki diğer tüm öğelerle karşılaştırmanız gereken yavaş bir yaklaşım kullanmanız gerekir.


4
Bu, paylaşılamayan liste öğeleri için geçerli değildir (örneğin, bir liste listesi)
KNejad

3
@KNejad Son paragrafın belirttiği şey budur.
dürtmek

Hata! Her şeyi okumalıydım. Yaptığım şey, bu yaklaşımın hala işe yarayabileceği şekilde listeler yerine tuples kullanmaktı.
KNejad

bunu örneğe ekleyin, t = [3, 2, 1, 1, 2, 5, 6, 7, 8], farkı açıkça gösterir!
sailfish009

“... önce bir sözlük oluşturma yükü ... Eğer siparişi korumanız gerekmiyorsa, bir küme kullanmaktan daha iyi olursunuz.” - Bunu profilledim çünkü bunun gerçekten doğru olup olmadığını merak ediyordum. Zamanlamalarım, setin gerçekten biraz daha hızlı olduğunu gösterir: 1M döngüleri boyunca 1M döngüleri boyunca yaklaşık 4 sn mutlak zaman farkı olan döngü başına 1.12 µs (set) vs döngü başına 1.53 µs (dikte). Yani bunu sıkı bir iç döngüde yapıyorsanız, umursamazsınız, aksi halde muhtemelen değil.
millerdev

414

Python 2.7'de , kopyaları orijinal sırada tutarken yinelenenleri kaldırmanın yeni yolu:

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

Python 3.5'te, OrderedDict'in bir C uygulaması vardır. Zamanlamalarım, bunun artık Python 3.5 için çeşitli yaklaşımların hem en hızlı hem de en kısa olduğunu gösteriyor.

Python 3.6'da düzenli diksiyon hem düzenli hem de kompakt hale geldi. (Bu özellik CPython ve PyPy için geçerlidir, ancak diğer uygulamalarda bulunmayabilir). Bu, siparişi korurken bize yeni ve hızlı bir tekilleştirme yolu sağlar:

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

Python 3.7'de normal diktenin her iki uygulamada da sipariş edilmesi garanti edilir. Yani, en kısa ve en hızlı çözüm:

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

10
Bence öğeleri düzenli tutmanın tek yolu bu.
Herberth Amaral


5
@MartijnPieters Düzeltme: Bence öğeleri düzenli tutmanın tek basit yolu bu .
Herberth Amaral

12
Bunun için orijinal listenin içeriği yıkanabilir olmalıdır
Davide

@Davide'ın belirttiği gibi, orijinal liste yıkanabilir olmalıdır. Bu, sözlüklerin bir listesi için çalışmadığı anlamına gelir. TypeError: unhashable type: 'dictlist'
CraZ

187

Tek satırlık: list(set(source_list))hile yapacak.

A set, çoğaltılamayacak bir şeydir.

Güncelleme: sipariş koruma yaklaşımı iki satırdır:

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

Burada OrderedDict, anahtarların ekleme sırasını hatırlayan ve belirli bir anahtardaki bir değer güncellendiğinde değişmeyen gerçeği kullanıyoruz . Değer Trueolarak ekleriz, ancak herhangi bir şey ekleyebiliriz, değerler kullanılmaz. ( yok sayılan değerlerle setçok benzer şekilde çalışır dict.)


5
Bu sadece source_listyıkanabilir olduğunda çalışır.
Adrian Keister

@AdrianKeister: Bu doğru. Eşitlik anlambilimine sahip ancak yıkanabilir olmayan nesneler vardır, örneğin listeler. OTOH, hastable gibi bir kısayolumuz yoksa, her elemanı şu anda bilinen tüm benzersiz unsurlarla karşılaştırmak için ikinci dereceden bir algoritma ile sonuçlanır. Bu, kısa girişler için, özellikle de çok sayıda yinelemeyle tamamen TAMAM olabilir.
9000

Aynen öyle. Bu çok yaygın kullanım durumunu dikkate alırsanız cevabınızın daha kaliteli olacağını düşünüyorum.
Adrian Keister

94
>>> 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
Bu yöntemin O (n ^ 2) sürede çalıştığını ve bu nedenle büyük listelerde çok yavaş olduğunu unutmayın.
dotancohen

@Chris_Rands: frozensetYıkanamayan içerikle çalıştığından emin değilim. Kullanırken hala yıkanamayan hata alıyorum frozenset.
Adrian Keister

85

Siparişi umursamıyorsanız, sadece bunu yapın:

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

A'nın setkopya olmaması garanti edilir.


3
lYıkanabilir olmadığı sürece çalışmaz.
Adrian Keister

41

Kopyaların ilk öğelerinin sırasını koruyarak yeni bir liste oluşturmak için L

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

örneğin if L=[1, 2, 2, 3, 4, 2, 4, 3, 5]o newlistzaman olacak[1,2,3,4,5]

Bu, her yeni öğenin eklenmeden önce listede daha önce görünmediğini kontrol eder. Ayrıca ithalata ihtiyaç duymaz.


3
Bunun O zaman karmaşıklığı vardır (n ^ 2) . İle verilen setve OrderedDictdaha düşük itfa edilmiş zaman karmaşıklığına sahip olabilir.
blubberdiblub


@blubberdiblub, set ve OrderedDict'ta daha az zaman harcayabilecek daha fazla kod etkin mekanizmanın mevcut olduğunu açıklayabilir misiniz? (onları yükleme yükü hariç)
ilias iliadis

olağan uygulamaları @iliasiliadis grubu ve dict kullanımı karma veya ağaç (dengelenmiş bir tür). Sen inşa düşünmek zorundayız setini veya dicti (birden çok kez) ve içinde arama yapan ancak itfa edilmiş karmaşıklık genellikle hala daha düşüktür O (n ^ 2) . Basit anlamda "itfa edilmiş" ortalama (ortalama karmaşıklıktan daha yüksek karmaşıklığa sahip en kötü vakaları olabilir) anlamına gelir. Bu yalnızca çok sayıda öğeniz olduğunda geçerlidir.
blubberdiblub

25

Bir meslektaşım bugünkü kodlama için kabul edilen cevabı kodunun bir parçası olarak bana gönderdi. Söz konusu cevabın zarafetine kesinlikle hayranım, ancak performanstan memnun değilim. Bu çözümü denedim ( arama süresini azaltmak için set kullanıyorum )

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

Verimliliği karşılaştırmak için 100 tamsayıdan oluşan rastgele bir örnek kullandım - 62 benzersizdi

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

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

İşte ölçümlerin sonuçları

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

Peki, set çözeltiden çıkarılırsa ne olur?

def ordered_set(inlist):
    out_list = []
    for val in inlist:
        if not val in out_list:
            out_list.append(val)
    return out_list

Sonuç, OrdereredDict kadar kötü değil , ancak orijinal çözümün 3 katından fazla

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

Döngü karşılaştırmasını hızlandırmak için set hızlı aramayı kullanarak güzel. Eğer sipariş önemli değilse (set (x)) hala bundan 6 kat daha hızlı
Joop

@İşte, bu meslektaşım için ilk sorumdu - emir önemli; aksi halde önemsiz bir sorun olurdu
volkan

ilgilenen herkes için sipariş seti optimize versiyonu 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

Pandalar ve Numpy'yi kullanan çözümler de var. Her ikisi de numpy dizisini döndürür, böylece .tolist()bir liste istiyorsanız işlevi kullanmanız gerekir .

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

Pandalar çözümü

Pandalar işlevini kullanma unique():

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

Numpy çözümü

Numpy işlevini kullanma unique().

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

Numpy.unique () öğesinin de değerleri sıraladığını unutmayın . Böylece liste t2sıralı olarak döndürülür. Siparişin korunmasını istiyorsanız bu cevaptaki gibi kullanın :

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

Çözüm, diğerlerine kıyasla çok zarif değil, ancak pandas.unique (), numpy.unique (), iç içe dizilerin seçilen bir eksen boyunca benzersiz olup olmadığını kontrol etmenizi sağlar.


Bu, listeyi dağınık olan ve dizeler için çalışmayan numpy dizisine dönüştürür.
user227666

1
@ user227666 İncelemeniz için teşekkürler, ancak dize ile bile çalıştığı doğru değil ve bir liste almak istiyorsanız .tolist ekleyebilirsiniz ...
GM

1
Sanırım bu bir balyozla bir arıyı öldürmeye çalışmak gibi. Kesinlikle! Ancak, bu amaçla bir kütüphaneyi içe aktarmak biraz fazla olabilir, değil mi?
Debosmit Ray

@DebosmitRay genellikle numpy ile çalıştığınız ve birçok kez numpy dizisiyle çalışmanız gereken Veri Bilimi'nde çalışmanız yararlı olabilir.
GM

2020 yılında en iyi cevap @DebosmitRay Umarım fikrini değiştirmek ve her zaman mümkün numpy / pandalar kullanmak
Egos

21

Başka bir yol:

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

1
Modern Python sürümlerinde (2.7+ sanırım, ama kesinlikle hatırlamıyorum), keys()bir liste değil bir sözlük görüntüleme nesnesi döndürür.
Dustin Wyatt

16

Basit ve kolay:

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

Çıktı:

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

5
kuadratik karmaşıklık yine de - inO (n) operasyonu ve cleanlisten fazla nsayıda = = en kötü durumda ~ O (n ^ 2)
jermenkoo

6
Liste anlama yan etkiler için kullanılmamalıdır.
Jean-François Fabre

13

Bu cevapta iki bölüm olacak: İki benzersiz çözüm ve belirli çözümler için bir hız grafiği.

Yinelenen Öğeleri Kaldırma

Bu cevapların çoğu sadece yıkanabilir yinelenen öğeleri kaldırır , ancak bu soru sadece yıkanabilir öğelere ihtiyaç duymadığı anlamına gelmez , yani yıkanabilir öğeler gerektirmeyen bazı çözümler sunacağım .

Counter , standart kütüphanede bunun için mükemmel olabilecek güçlü bir araçtır. Counter bile olan başka bir çözüm daha var. Ancak bu çözüm, yıkanabilir tuşlarla da sınırlıdır .

Sayaç'ta paylaşılamayan anahtarlara izin vermek için, nesnenin varsayılan karma işlevini almaya çalışacak bir Container sınıfı yaptım, ancak başarısız olursa, kimlik işlevini deneyecek. Aynı zamanda bir eq ve hash yöntemini tanımlar . Bu, çözümümüzde paylaşılamaz öğelere izin vermek için yeterli olmalıdır . Shahable nesnelere yıkanabilirmiş gibi davranılır. Ancak, bu karma işlevi, paylaşılamayan nesneler için kimlik kullanır, yani her ikisi de paylaşılamayan iki eşit nesne çalışmaz. Bunu geçersiz kılma ve kullanma gibi (eşdeğer bir değişken türü karmasını kullanmak değiştirmeyi önermek hash(tuple(my_list))eğermy_list bir list ).

İki çözüm de yaptım. 'OrderedCounter' adında bir OrdierDict ve Counter alt sınıfı kullanarak öğelerin sırasını koruyan başka bir çözüm. Şimdi, fonksiyonlar şunlardır:

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 sıralı değil, oremd sıralı. Hangisinin daha hızlı olduğunu açıkça anlayabilirsiniz, ama yine de açıklayacağım. Sıralanmamış sıralama biraz daha hızlıdır. Düzen gerektirmediği için daha az veri tutar.

Şimdi, her cevabın hız karşılaştırmalarını da göstermek istedim. Şimdi bunu yapacağım.

En Hızlı Hangi İşlev?

Kopyaları kaldırmak için, birkaç cevaptan 10 fonksiyon topladım. Her işlevin hızını hesapladım ve matplotlib.pyplot kullanarak bir grafiğe koydum .

Bunu üç grafik turuna ayırdım. Yıkanabilir hashedilebilen herhangi bir nesnedir, paylaşılamaz hash edilemeyen herhangi bir nesnedir. Sıralı bir sıra, düzeni koruyan bir sıradır, sırasız bir sıra sıralamayı korumaz. Şimdi, birkaç terim daha:

Sırasız Yıkanabilir , siparişleri korumak zorunda olmayan kopyaları kaldıran herhangi bir yöntem . Tıraşsızlar için çalışmak zorunda değildi, ama olabilirdi.

Sipariş Edilebilir Yıkanabilir , listedeki öğelerin sırasını koruyan herhangi bir yöntem içindi, ancak shahables için çalışmak zorunda değildi, ancak olabilirdi.

Shahable sipariş edildi , listedeki öğelerin sırasını koruyan ve için çalışan herhangi bir yöntemdi.

Y ekseninde geçen saniye miktarı.

X ekseninde, işlevin uygulandığı sayıdır.

Sırasız hashable'lar için diziler oluşturduk ve aşağıdaki kavrayışla hashables sipariş ettik: [list(range(x)) + list(range(x)) for x in range(0, 1000, 10)]

Sipariş edilen unhashables için: [[list(range(y)) + list(range(y)) for y in range(x)] for x in range(0, 1000, 10)]

Aralıkta bir 'adım' olduğuna dikkat edin, çünkü onsuz bu 10 kat daha uzun sürecektir. Ayrıca kişisel görüşüme göre, okunması biraz daha kolay görünebileceğini düşündüm.

Ayrıca, efsane üzerindeki tuşların, işlevin en önemli parçaları olarak tahmin etmeye çalıştığım şeyler olduğuna dikkat edin. En kötü ya da en iyi hangi işlev için? Grafik kendisi için konuşur.

Bu kararla birlikte, grafikler burada.

Sırasız Hashables

resim açıklamasını buraya girin (Yakınlaştırılmış) resim açıklamasını buraya girin

Sipariş Edilen Hashables

resim açıklamasını buraya girin (Yakınlaştırılmış) resim açıklamasını buraya girin

Sipariş Edilemeyen Shahables

resim açıklamasını buraya girin (Yakınlaştırılmış) resim açıklamasını buraya girin


11

Listemde bir karar vardı, bu yüzden yukarıdaki yaklaşımı kullanamadım. Hatayı aldım:

TypeError: unhashable type:

Bu yüzden sipariş ve / veya bazı öğeler umursamaz iseniz shahable . O zaman bunu yararlı bulabilirsiniz:

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

Bazıları, yan etkisi olan liste kavrayışının iyi bir çözüm olmadığını düşünebilir. İşte bir 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

6
mapbir yan etki ile bir yan etki ile bir liste comp daha da yanıltıcıdır. Ayrıca, lambda x: unique_list.append(x)sadece daha zor ve daha yavaş bir yoludur unique_list.append.
abarnert

Öğeleri tek bir satıra eklemenin çok faydalı bir yolu, teşekkürler!
ZLNK

2
@ZLNK lütfen, bunu asla kullanma. Kavramsal olarak çirkin olmanın yanı sıra, son derece verimsizdir, çünkü aslında potansiyel olarak büyük bir liste oluşturursunuz ve sadece temel yinelemeyi gerçekleştirmek için atarsınız.
Eli Korvigo

10

Burada şimdiye kadar gördüğüm tüm sipariş koruma yaklaşımları ya saf karşılaştırma (en iyi O (n ^ 2) zaman karmaşıklığı ile) ya da yıkanabilir girdilerle sınırlı ağır OrderedDicts/ set+ listkombinasyonları kullanır. İşte karma bağımsız O (nlogn) çözümü:

Güncellemekey argüman, dokümantasyon ve Python 3 uyumluluğunu ekledi .

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

Yine de, bu çözüm düzenlenebilir elemanlar gerektirir. Listelerimi benzersiz bir şekilde kullanacağım: listeleri listelemek ve özetlemek için bir acıdır tuple(). | | | | - Genel olarak, karma işlemi tüm verilerin boyutuyla orantılı bir zaman alırken, bu çözüm sadece listenin uzunluğuna bağlı olarak O (nlog (n)) zamanını alır.
loxaxs

Küme temelli yaklaşımın, sıralama + benzersizlerin saptanmasından daha ucuz (O (n log n)) veya daha ucuz olduğunu düşünüyorum. (Yine de bu yaklaşım çok daha iyi paralellik gösterir.) Aynı zamanda başlangıç ​​düzenini tam olarak korumaz, ancak öngörülebilir bir düzen verir.
9000

@ 9000 Bu doğru. Açıkça O (n) olan karma tablo tabanlı bir yaklaşımın zaman karmaşıklığından hiç bahsetmedim. Burada hash tablolarını içeren birçok cevap bulabilirsiniz. Yine de evrensel değillerdir, çünkü nesnelerin yıkanabilir olmasını gerektirirler. Dahası, çok daha fazla bellek yoğun.
Eli Korvigo

Bu cevabı okumak ve anlamak zaman alır. Endeksleri kullanmadığınızda numaralandırmanın bir anlamı var mı? reduce() Zaten Sıralanmış koleksiyonu üzerinde çalışıyor srt_enumbaşvurdun neden sortedtekrar?
Brayoni

@Brayoni eşit değer gruplamak için ilk sıralama var, ikinci sıralama ilk sipariş geri yüklemek için var. Numaralandırma, orijinal göreli düzeni takip etmek için gereklidir.
Eli Korvigo

9

Siparişi korumak ve burada herhangi bir harici modül kullanmak istemiyorsanız, bunu yapmanın kolay bir yoludur:

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

Not: Bu yöntem görünüm sırasını korur, bu nedenle, yukarıda görüldüğü gibi, dokuz ilk kez geldiği için birbiri ardına gelecek. Ancak bu, yaptığınız sonuçla aynı sonuçtur.

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

ama çok daha kısadır ve daha hızlı çalışır.

Bu, fromkeysişlev her yeni anahtar oluşturmaya çalıştığında çalışır, eğer değer zaten varsa basitçe üzerine yazılır. Ancak, fromkeystüm anahtarların değere sahip olduğu bir sözlük oluşturduğundan , sözlüğü hiç etkilemez None, bu nedenle tüm kopyaları bu şekilde etkili bir şekilde ortadan kaldırır.


Ayrıca burada
vineeshvs

8

Bunu da yapabilirsiniz:

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

Yukarıdaki çalışmanın nedeni, indexyöntemin bir öğenin yalnızca ilk dizinini döndürmesidir. Yinelenen öğelerin dizinleri daha yüksektir. Buraya bakın :

list.index (x [, start [, end]])
Değeri x olan ilk öğe listesinde sıfır temelli dizin döndürür. Böyle bir öğe yoksa bir ValueError değerini yükseltir.


Bu çok verimsiz. list.indexçözümünüzü ikinci dereceden yapan doğrusal bir işlemdir.
Eli Korvigo

Haklısın. Ama aynı zamanda çözümün düzeni koruyan tek bir astar olması amaçlandığına inanıyorum. Diğer her şey zaten burada.
Atonal

7

Kümeleri kullanmayı deneyin:

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

print t | t1
print t - t1

7

Sipariş koruyarak varyantı azaltın:

Listemiz olduğunu varsayalım:

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

Varyasyonu azaltın (verimsiz):

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

5 kat daha hızlı ama daha sofistike

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

Açıklama:

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

Bir listeden yinelenenleri kaldırmanın en iyi yaklaşımı, python'da bulunan set () işlevini kullanmaktır ve yine bu seti listeye dönüştürmektir.

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 memnun.!
Anurag Misra

Yeni listeler ve kümeler oluşturmak ücretsiz değildir. Bunu birçok kez hızlı bir şekilde (yani çok sıkı bir döngüde) yaparsak ve listeler çok küçükse ne olur?
Z4 katmanlı

6

Aşağıdaki işlevi kullanabilirsiniz:

def rem_dupes(dup_list): 
    yooneeks = [] 
    for elem in dup_list: 
        if elem not in yooneeks: 
            yooneeks.append(elem) 
    return yooneeks

Örnek :

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

Kullanımı:

rem_dupes(my_list)

['this', '', 'a', 'liste', 'ile', 'kopyalar', 'in', 'the']


5

Bunu yapmanın farklı yollarını öneren birçok cevap var, ancak hepsi toplu işlemler ve bazıları orijinal siparişi atıyor. İhtiyacınız olan şeye bağlı olarak bu uygun olabilir, ancak her bir değerin ilk örneğinin sırasına göre değerler üzerinde yineleme yapmak istiyorsanız ve kopyaları anında ve anında bir kerede kaldırmak istiyorsanız, bu jeneratör:

def uniqify(iterable):
    seen = set()
    for item in iterable:
        if item not in seen:
            seen.add(item)
            yield item

Bu bir jeneratör / yineleyici döndürür, böylece yineleyici kullanabileceğiniz herhangi bir yerde kullanabilirsiniz.

for unique_item in uniqify([1, 2, 3, 4, 3, 2, 4, 5, 6, 7, 6, 8, 8]):
    print(unique_item, end=' ')

print()

Çıktı:

1 2 3 4 5 6 7 8

Bir istiyorsanız list, bunu yapabilirsiniz:

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

print(unique_list)

Çıktı:

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

seen = set(iterable); for item in seen: yield itemneredeyse kesinlikle daha hızlı. (Bu özel davayı denemedim, ama bu benim tahminim olurdu.)
dylnmc

2
@dylnmc, bu bir toplu işlemdir ve siparişini de kaybeder. Cevabım özellikle anında ve ilk sırada olma amacına yönelikti. :)
Cyphase

5

Set kullanmadan

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

setKopyaları kaldırmak için kullanabilirsiniz :

mylist = list(set(mylist))

Ancak sonuçların sırasız olacağını unutmayın. Bu bir sorunsa:

mylist.sort()

1
Şunları yapabilirsiniz: mylist = sıralanmış (liste (set (
mylist

5

Daha iyi bir yaklaşım,

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]

ve düzen korunur.


Bu işe yarayabilse de, bu amaçla pandalar gibi ağır bir kütüphane kullanmak aşırıya kaçmış gibi görünüyor.
Glutexo

4

Bu çok fazla güçlük (OrderdDict & diğerleri) olmadan sipariş umurunda. Muhtemelen en Pythonic yolu ya da en kısa yolu değil, hile yapar:

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. Yerleşik isimleri asla gölgelememelisiniz (en azından, kadar önemli list); 2. Metodunuz çok kötü ölçekleniyor: içindeki elemanların sayısı ikinci dereceden list.
Eli Korvigo

1. Doğru, ama bu bir örnekti; 2. Doğru, ve tam da bunu teklif etmemin sebebi. Burada yayınlanan tüm çözümlerin artıları ve eksileri vardır. Bazıları sadeliği veya düzeni feda eder, mayın ölçeklenebilirliği feda eder.
cgf

Bu bir "Shlemiel the ressam" algoritması ...
Z4-katmanlı

4

Aşağıdaki kod, yinelenenleri listeden kaldırmak için basittir

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

geri döner [1,2,3,4]


2
Siparişi umursamıyorsanız, bu önemli ölçüde daha uzun sürer. list(set(..))(1 milyondan fazla geçiş) bu çözümü yaklaşık 10 saniye yenecek - oysa bu yaklaşım yaklaşık 12 saniye sürecek, list(set(..))sadece 2 saniye sürecek !
dylnmc

@dylnmc bu da oldukça eski bir cevabın
Eli Korvigo

4

Yanıtlarda listelenen diğerlerine hitap eden en hızlı pythonic çözümü.

Kısa devre değerlendirmesinin uygulama detaylarını kullanmak, yeterince hızlı olan liste kavrayışının kullanılmasına izin verir. visited.add(item)her zaman Nonesonuç olarak geri döner ve Falsebu şekildeor her zaman böyle bir ifadenin sonucu olur.

Kendiniz zamanlayın

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

Set kullanarak :

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

Benzersiz kullanma :

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

4

Ne yazık ki. Buradaki cevapların çoğu ya siparişi korumuyor ya da çok uzun. İşte basit, siparişi koruyan bir cevap.

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)

Bu, kopyaları kaldırılmış ancak siparişi korurken x'i verecektir.


3

Python 3'te çok basit bir yol:

>>> 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(...))gereksizdir ( sortedzaten örtük olarak argümanını yeniye dönüştürür list, sıralar, sonra yenisini döndürür list, bu nedenle her iki yöntemi kullanarak gereksiz bir geçici hale getirir list). Yalnızca listsonucun sıralanması gerekmiyorsa kullanın, yalnızca sonucun sıralanması sortedgerekiyorsa kullanın.
ShadowRanger

3

Python'un Büyüsü Dahili tip

Python'da, bu gibi karmaşık vakaları ve sadece python'un yerleşik tipiyle işlemek çok kolaydır.

Size nasıl yapılacağını göstereyim!

Yöntem 1: Genel Durum

Listedeki yinelenen öğeyi kaldırma ve sıralama düzenini korumaya devam etme yolu ( 1 satır kodu )

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

Sonucu alacaksın

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

Yöntem 2: Özel Durum

TypeError: unhashable type: 'list'

Shashable işlemek için özel durum ( 3 satır kodu )

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)

Sonucu alacaksınız:

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

Tuple yıkanabilir olduğundan ve liste ile tuple arasında kolayca veri dönüştürebilirsiniz

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.