Destul de mult am nevoie pentru a scrie un program pentru a verifica daca o lista are orice duplicate și dacă nu se elimină-le și întoarce o nouă listă cu elementele care au fost't duplicat/eliminat. Aceasta este ceea ce am, dar sincer să fiu nu știu ce să fac.
def remove_duplicates():
t = ['a', 'b', 'c', 'd']
t2 = ['a', 'c', 'd']
for t in t2:
t.append(t.remove())
return t
Abordarea comună pentru a obține o colecție unică de elemente este de a utiliza un set. Seturi sunt neordonate colecții de distincte obiecte. Pentru a crea un set de la orice iterable, puteți trece pur și simplu la built-in [set()
](http://docs.python.org/3/library/functions.html#func-set funcția). Dacă mai târziu nevoie de o lista din nou, în mod similar, puteți trece setat la [lista()
](http://docs.python.org/3/library/functions.html#func-list funcția).
Următorul exemplu ar trebui să acopere orice ai încerca să faci:
>>> 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]
După cum puteți vedea din exemplul urmare, ordinea inițială nu este menținută. După cum sa menționat mai sus, seturi înșiși sunt colecții neordonate, deci ordinea este pierdut. Când se face conversia de la un set înapoi la o listă, o ordine arbitrară este creat.
Dacă scopul este de important pentru tine, atunci va trebui să utilizați un mecanism diferit. O soluție comună pentru acest lucru este să se bazeze pe OrderedDict
să păstreze ordinea de chei timpul de inserție:
>>> from collections import OrderedDict
>>> list(OrderedDict.fromkeys(t))
[1, 2, 3, 5, 6, 7, 8]
Începând cu Python 3.7, built-in dicționar este garantat pentru a menține inserție pentru ca de bine, astfel încât să puteți utiliza, de asemenea, că în mod direct, dacă sunteți pe Python 3.7 sau mai târziu (sau CPython 3.6):
>>> list(dict.fromkeys(t))
[1, 2, 3, 5, 6, 7, 8]
Rețineți că acest lucru are aeriene de a crea un dicționar în primul rând, și apoi a crea o listă de la ea. Dacă nu aveți de fapt nevoie pentru a păstra ordinea, esti mai bine folosind un set. Check out această întrebare pentru mai multe detalii și modalități alternative de a păstra ordinea, atunci când eliminarea duplicatelor.
În cele din urmă act de faptul că atât "set", precum și OrderedDict/
dict soluții nevoie de un produs pentru a fi hashable. De obicei, aceasta înseamnă că ei trebuie să fie imuabile. Dacă ai de-a face cu elemente care nu sunt hashable (de exemplu, lista de obiecte), atunci va trebui să utilizați o abordare lent în care va în principiu, trebuie să compară fiecare element cu fiecare alt element într-o buclă imbricată.
În Python 2.7, noul mod de a scoate duplicate dintr-un iterable în timp ce menținându-l în ordinea inițială este:
>>> from collections import OrderedDict
>>> list(OrderedDict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']
În Python 3.5, la OrderedDict are o implementare C. Timpii mei arată că acest lucru este cel mai rapid și cel mai scurt de diverse abordări pentru Python 3.5.
În Python 3.6, regulat dict a devenit atât de ordonat si compact. (Această caracteristică este valabil pentru CPython și PyPy dar nu poate prezenta în alte implementări). Asta ne dă un nou cel mai rapid mod de deduping păstrând în același timp pentru:
>>> list(dict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']
În Python 3.7, regulat dict este garantat pentru a comandat peste toate implementările. Deci, cea mai scurtă și mai rapidă soluție este:
>>> list(dict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']
L's o o-liner: lista(set(source_list))` va face truc.
Un " set " este ceva care poate't, eventual, au duplicate.
Update: un ordin de conservare abordare este de două linii:
from collections import OrderedDict
OrderedDict((x, True) for x in source_list).keys()
Aici vom folosi faptul că OrderedDict
își amintește de inserție scopul de chei, și să nu-l schimbe atunci când o valoare la o anumită cheie este actualizat. Vom introduce "Adevărat" ca valori, dar putem introduce nimic, valorile nu sunt utilizate. ("set" funcționează ca un dict
cu ignorate de valori, de asemenea.)
Pentru a face o nouă listă de fixare ordinea de primele elemente de duplicate în L
newlist=[ii pentru n,ii enumera(L) dacă a ii-a nu L[:n]]
de exemplu, dacă Am=[1, 2, 2, 3, 4, 2, 4, 3, 5]`` apoi ``newlist
va fi [1,2,3,4,5]
Acest pas se verifică fiecare element nou nu a apărut anterior în lista înainte de a o adăuga. De asemenea, nu are nevoie de importuri.
Un coleg a trimis răspunsul acceptat ca parte din codul lui la mine pentru un codereview astăzi. În timp ce eu admir eleganta de a răspunde la întrebare, eu nu sunt fericit cu performanța. Am încercat această soluție (eu folosesc set pentru a reduce căutare de timp)
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
Pentru a compara eficiența, am folosit un eșantion aleatoriu de 100 de numere întregi - 62 au fost unice
from random import randint
x = [randint(0,100) for _ in xrange(100)]
In [131]: len(set(x))
Out[131]: 62
Aici sunt rezultatele măsurătorilor
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
Ei bine, ce se întâmplă dacă setul este îndepărtat din soluție?
def ordered_set(inlist):
out_list = []
for val in inlist:
if not val in out_list:
out_list.append(val)
return out_list
Rezultatul nu este la fel de rău ca și cu OrderedDict, dar încă mai mult de 3 ori de soluția inițială
In [136]: %timeit ordered_set(x)
10000 loops, best of 3: 52.6 us per loop
Există, de asemenea, soluții folosind Panda și Numpy. Amândoi se întoarcă numpy matrice deci va trebui să utilizați funcția .tolist()
dacă doriți o listă.
t=['a','a','b','b','b','c','c','c']
t2= ['c','c','b','b','b','a','a','a']
Folosind Panda funcția unic()
:
import pandas as pd
pd.unique(t).tolist()
>>>['a','b','c']
pd.unique(t2).tolist()
>>>['c','b','a']
Folosind numpy funcția unic()
.
import numpy as np
np.unique(t).tolist()
>>>['a','b','c']
np.unique(t2).tolist()
>>>['a','b','c']
Rețineți că numpy.unic (), de asemenea, un fel de valori. Deci lista " t2 " este returnat-a rezolvat. Dacă doriți să aveți pentru conservate utilizare ca în acest răspuns:
_, idx = np.unique(t2, return_index=True)
t2[np.sort(idx)].tolist()
>>>['c','b','a']
Soluția nu este atât de elegant în comparație cu alții, cu toate acestea, în comparație cu panda.unic(), numpy.unic() vă permite, de asemenea, pentru a verifica dacă tablouri imbricate sunt unice de-a lungul o anumită axă.
Am avut un dict în lista mea, așa că nu am putut folosi metoda de mai sus. Am eroarea:
TypeError: unhashable type:
Deci, dacă îți pasă pentru și/sau unele elemente sunt unhashable. Atunci s-ar putea găsi acest util:
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
Unii ar putea lua în considerare lista de înțelegere cu un efect secundar de a nu fi o soluție bună. Aici's o alternativă:
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
Tot pentru menținerea abordărilor I'am văzut aici, atât de departe folosi fie naiv comparație (cu O(n^2) timp-complexitatea în cel mai bun) sau cu greutate grele OrderedDicts
/ " set " + "listă" de combinații, care sunt limitate la hashable intrări. Aici este un hash-independent de O(nlogn) soluție:
Update adăugat "cheia" de argument, documentare și Python 3 compatibilitate.
# 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]]))]
Dacă doriți să păstreze ordinea, și nu folosi orice module externe aici este o modalitate ușoară de a face acest lucru:
``python
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ă: Această metodă păstrează ordinea de apariție, așa cum am văzut mai sus, nouă va veni după o pentru că a fost prima dată când a apărut. Acest lucru însă, este același rezultat ca te-ar primi cu
python din colecțiile de import OrderedDict ulist=lista(OrderedDict.fromkeys(l))
dar este mult mai scurt, și rulează mai rapid.
Acest lucru funcționează pentru că de fiecare dată când fromkeys funcția încearcă să creeze o nouă cheie, dacă valoarea deja există pur și simplu se va suprascrie. Acest lucru va afecta dicționar deloc cu toate acestea, ca
fromkeys` creează un dicționar în care toate cheile au valoarea "Nici unul", în mod eficient, astfel se elimina toate duplicatele acest fel.
Ai putea, de asemenea, face acest lucru:
>>> 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]
Motivul pentru care funcționează de mai sus este că "index" metoda returnează doar primul indice al unui element. Elemente duplicat fi mai mari indici. Consultați aici:
listă.index(x[, start[, end]]) Return index bazat pe zero în lista de primul element a cărui valoare este x. Ridică o ValueError dacă nu există nici un astfel de element.
Reducerea varianta cu comanda conserva:
Să presupunem că avem lista:
l = [5, 6, 6, 1, 1, 2, 2, 3, 4]
Reduce variant (unefficient):
>>> reduce(lambda r, v: v in r and r or r + [v], l, [])
[5, 6, 1, 2, 3, 4]
5 x mai rapid, dar mult mai sofisticat
>>> 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]
Explicație:
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]
Puteți utiliza următoarele funcții:
def rem_dupes(dup_list):
yooneeks = []
for elem in dup_list:
if elem not in yooneeks:
yooneeks.append(elem)
return yooneeks
Exemplu:
my_list = ['this','is','a','list','with','dupicates','in', 'the', 'list']
Utilizare:
rem_dupes(my_list)
['asta', 'este', 'un', 'list', 'cu', 'dupicates', 'in', 'la']
Cea mai bună abordare de eliminarea duplicate dintr-o listă se utilizează set() funcție disponibilă în python, din nou, convertirea setați în listă
In [2]: some_list = ['a','a','v','v','v','c','c','d']
In [3]: list(set(some_list))
Out[3]: ['a', 'c', 'd', 'v']
Există multe alte răspunsuri sugerează diferite moduri de a face acest lucru, dar ei're toate operațiunile de lot, iar unele dintre ele arunca ordinea inițială. Care ar putea fi bine în funcție de ceea ce aveți nevoie, dar dacă vrei să itera peste valorile în ordinea de primă instanță din fiecare valoare, și doriți pentru a elimina duplicatele de pe-the-fly față de toate la o dată, ai putea folosi acest generator:
def uniqify(iterable):
seen = set()
for item in iterable:
if item not in seen:
seen.add(item)
yield item
Acesta returnează un generator/iterator, astfel încât să puteți folosi oriunde pe care le puteți folosi un iterator.
for unique_item in uniqify([1, 2, 3, 4, 3, 2, 4, 5, 6, 7, 6, 8, 8]):
print(unique_item, end=' ')
print()
Ieșire:
1 2 3 4 5 6 7 8
Daca vrei o "listă", puteți face acest lucru:
unique_list = list(uniqify([1, 2, 3, 4, 3, 2, 4, 5, 6, 7, 6, 8, 8]))
print(unique_list)
Ieșire:
[1, 2, 3, 4, 5, 6, 7, 8]