Yanıtlar:
Kullanım set()
tüm değerler ise çiftleri kaldırmak hashable :
>>> your_list = ['one', 'two', 'one']
>>> len(your_list) != len(set(your_list))
True
Yalnızca kısa listeler için önerilir :
any(thelist.count(x) > 1 for x in thelist)
Do not uzun bir liste üzerinde kullanmak - bu zamanı orantılı alabilir meydanda listesindeki öğelerin sayısının!
Yıkanabilir öğelere sahip daha uzun listeler için (dizeler, sayılar ve c):
def anydup(thelist):
seen = set()
for x in thelist:
if x in seen: return True
seen.add(x)
return False
Öğeleriniz yıkanamazsa (alt listeler, diktler, vb.) Saçlar daha da kızarır, ancak en azından karşılaştırılabilir olmaları durumunda O (N logN) almak yine de mümkün olabilir. Ancak, yapabileceğiniz en iyi performansı elde etmek için öğelerin özelliklerini (yıkanabilir veya değil, karşılaştırılabilir veya değil) bilmeniz veya test etmeniz gerekir - Yıkanabilirler için O (N), yıkanamaz karşılaştırılabilirler için O (N log N), aksi takdirde O (N kare) aşağı ve bu konuda yapabileceği bir şey yok :-(.
all
her şeyden önce sayımların 1 olması gerekir). Tüm değerlere sahip bir diksiyon Ayrıca, sizin de bahsettiğiniz, bir set
katma değeri olmayan, gülünç, yararsız bir şekilde şişirilmiş bir taklitçidir . Big-O programlamada her şey değildir.
Bu eski, ama buradaki cevaplar beni biraz farklı bir çözüme götürdü. Anlayışları kötüye kullanmak istiyorsanız, bu şekilde kısa devre yapabilirsiniz.
xs = [1, 2, 1]
s = set()
any(x in s or s.add(x) for x in xs)
# You can use a similar approach to actually retrieve the duplicates.
s = set()
duplicates = set(x for x in xs if x in s or s.add(x))
İşlevsel programlama stilinden hoşlanıyorsanız, doctest kullanarak kullanışlı bir işlev, kendi kendine belgelenmiş ve test edilmiş kod .
def decompose(a_list):
"""Turns a list into a set of all elements and a set of duplicated elements.
Returns a pair of sets. The first one contains elements
that are found at least once in the list. The second one
contains elements that appear more than once.
>>> decompose([1,2,3,5,3,2,6])
(set([1, 2, 3, 5, 6]), set([2, 3]))
"""
return reduce(
lambda (u, d), o : (u.union([o]), d.union(u.intersection([o]))),
a_list,
(set(), set()))
if __name__ == "__main__":
import doctest
doctest.testmod()
Oradan, dönen çiftin ikinci elemanının boş olup olmadığını kontrol ederek tekliği test edebilirsiniz:
def is_set(l):
"""Test if there is no duplicate element in l.
>>> is_set([1,2,3])
True
>>> is_set([1,2,1])
False
>>> is_set([])
True
"""
return not decompose(l)[1]
Ayrıştırmayı açıkça oluşturduğunuz için bunun etkili olmadığını unutmayın. Ancak azaltma kullanma hattı boyunca, 5'i cevaplamak için eşdeğer (ancak biraz daha az verimli) bir şeye gelebilirsiniz:
def is_set(l):
try:
def func(s, o):
if o in s:
raise Exception
return s.union([o])
reduce(func, l, set())
return True
except:
return False
Burada sunulan farklı çözümlerin zamanlamalarını karşılaştırmanın yararlı olacağını düşündüm. Bunun için kendi kütüphanemi kullandım simple_benchmark
:
Gerçekten de bu durumda Denis Otkidach'ın çözümü en hızlı.
Bazı yaklaşımlar da çok daha dik bir eğri sergilemektedir, bunlar elementlerin sayısı ile ikinci dereceden ölçeklenen yaklaşımlardır (Alex Martellis ilk çözümü, wjandrea ve Xavier Decorets çözümlerinin her ikisi). Ayrıca, Keiku'nun panda çözümünün çok büyük bir sabit faktöre sahip olduğu da belirtilmelidir. Ancak daha büyük listeler için neredeyse diğer çözümlere yetişir.
Ve yinelenen ilk konumda olması durumunda. Hangi çözümlerin kısa devre yaptığını görmek için yararlıdır:
Burada birkaç yaklaşım kısa devre yapmaz: Kaiku, Frank, Xavier_Decoret (ilk çözüm), Turn, Alex Martelli (ilk çözüm) ve Denis Otkidach tarafından sunulan yaklaşım (kopyasız vakada en hızlı olan).
Buraya kendi kütüphanemden bir fonksiyon ekledim: iteration_utilities.all_distinct
bu, çoğaltılmamış durumda en hızlı çözümle rekabet edebilen ve başlangıçta çoğaltma vakası için sabit zamanda (en hızlı olmasa da) çalışan bir işlev içeriyordu .
Kıyaslama kodu:
from collections import Counter
from functools import reduce
import pandas as pd
from simple_benchmark import BenchmarkBuilder
from iteration_utilities import all_distinct
b = BenchmarkBuilder()
@b.add_function()
def Keiku(l):
return pd.Series(l).duplicated().sum() > 0
@b.add_function()
def Frank(num_list):
unique = []
dupes = []
for i in num_list:
if i not in unique:
unique.append(i)
else:
dupes.append(i)
if len(dupes) != 0:
return False
else:
return True
@b.add_function()
def wjandrea(iterable):
seen = []
for x in iterable:
if x in seen:
return True
seen.append(x)
return False
@b.add_function()
def user(iterable):
clean_elements_set = set()
clean_elements_set_add = clean_elements_set.add
for possible_duplicate_element in iterable:
if possible_duplicate_element in clean_elements_set:
return True
else:
clean_elements_set_add( possible_duplicate_element )
return False
@b.add_function()
def Turn(l):
return Counter(l).most_common()[0][1] > 1
def getDupes(l):
seen = set()
seen_add = seen.add
for x in l:
if x in seen or seen_add(x):
yield x
@b.add_function()
def F1Rumors(l):
try:
if next(getDupes(l)): return True # Found a dupe
except StopIteration:
pass
return False
def decompose(a_list):
return reduce(
lambda u, o : (u[0].union([o]), u[1].union(u[0].intersection([o]))),
a_list,
(set(), set()))
@b.add_function()
def Xavier_Decoret_1(l):
return not decompose(l)[1]
@b.add_function()
def Xavier_Decoret_2(l):
try:
def func(s, o):
if o in s:
raise Exception
return s.union([o])
reduce(func, l, set())
return True
except:
return False
@b.add_function()
def pyrospade(xs):
s = set()
return any(x in s or s.add(x) for x in xs)
@b.add_function()
def Alex_Martelli_1(thelist):
return any(thelist.count(x) > 1 for x in thelist)
@b.add_function()
def Alex_Martelli_2(thelist):
seen = set()
for x in thelist:
if x in seen: return True
seen.add(x)
return False
@b.add_function()
def Denis_Otkidach(your_list):
return len(your_list) != len(set(your_list))
@b.add_function()
def MSeifert04(l):
return not all_distinct(l)
Ve argümanlar için:
# No duplicate run
@b.add_arguments('list size')
def arguments():
for exp in range(2, 14):
size = 2**exp
yield size, list(range(size))
# Duplicate at beginning run
@b.add_arguments('list size')
def arguments():
for exp in range(2, 14):
size = 2**exp
yield size, [0, *list(range(size)]
# Running and plotting
r = b.run()
r.plot()
Kısa süre önce bir jeneratörü kullanarak listedeki tüm kopyaları oluşturmak için ilgili bir soruyu cevapladım . Sadece 'yinelenen varsa' oluşturmak için kullanılırsa, o zaman sadece ilk öğeyi almanız gerekir ve geri kalanı göz ardı edilebilir, bu da nihai kısayoldur.
Bu, doğrudan moooeeeep'ten uyarladığım ilginç bir set tabanlı yaklaşımdır :
def getDupes(l):
seen = set()
seen_add = seen.add
for x in l:
if x in seen or seen_add(x):
yield x
Buna göre, çiftlerin tam listesi olacaktır list(getDupes(etc))
. Bir "dupe" olup olmadığını basitçe test etmek için şu şekilde sarılmalıdır:
def hasDupes(l):
try:
if getDupes(l).next(): return True # Found a dupe
except StopIteration:
pass
return False
Bu iyi ölçeklendirilir ve dupe'nin listede olduğu her yerde tutarlı çalışma süreleri sağlar - 1 metreye kadar giriş listeleriyle test ettim. Veriler hakkında bir şey biliyorsanız, özellikle, çiftlerin ilk yarıda ortaya çıkması muhtemeldir veya gerçek dupes'i almak gibi gereksinimlerinizi eğmenize izin veren başka şeyler varsa, o zaman birkaç alternatif dupe bulucu vardır. daha iyi performans gösterebilir. Tavsiye ettiğim iki ...
Basit dict tabanlı yaklaşım, çok okunabilir:
def getDupes(c):
d = {}
for i in c:
if i in d:
if d[i]:
yield i
d[i] = False
else:
d[i] = True
Sıralanan listede itertools'tan (esas olarak bir ifilter / izip / tee) yararlanın, sadece ilkleri almak kadar hızlı olmasa da tüm dupes'leri alıyorsanız çok etkilidir:
def getDupes(c):
a, b = itertools.tee(sorted(c))
next(b, None)
r = None
for k, g in itertools.ifilter(lambda x: x[0]==x[1], itertools.izip(a, b)):
if k != r:
yield k
r = k
Bunlar tam dupe listesi için denediğim yaklaşımların en iyi performans göstericileriydi , ilk dupe başlangıçtan ortaya doğru 1m eleman listesinde herhangi bir yerde meydana geldi. Sıralama adımının ne kadar az ek yük oluşturduğu şaşırtıcıydı. Kilometreniz değişebilir, ancak işte belirli zamanlanmış sonuçlarım:
Finding FIRST duplicate, single dupe places "n" elements in to 1m element array
Test set len change : 50 - . . . . . -- 0.002
Test in dict : 50 - . . . . . -- 0.002
Test in set : 50 - . . . . . -- 0.002
Test sort/adjacent : 50 - . . . . . -- 0.023
Test sort/groupby : 50 - . . . . . -- 0.026
Test sort/zip : 50 - . . . . . -- 1.102
Test sort/izip : 50 - . . . . . -- 0.035
Test sort/tee/izip : 50 - . . . . . -- 0.024
Test moooeeeep : 50 - . . . . . -- 0.001 *
Test iter*/sorted : 50 - . . . . . -- 0.027
Test set len change : 5000 - . . . . . -- 0.017
Test in dict : 5000 - . . . . . -- 0.003 *
Test in set : 5000 - . . . . . -- 0.004
Test sort/adjacent : 5000 - . . . . . -- 0.031
Test sort/groupby : 5000 - . . . . . -- 0.035
Test sort/zip : 5000 - . . . . . -- 1.080
Test sort/izip : 5000 - . . . . . -- 0.043
Test sort/tee/izip : 5000 - . . . . . -- 0.031
Test moooeeeep : 5000 - . . . . . -- 0.003 *
Test iter*/sorted : 5000 - . . . . . -- 0.031
Test set len change : 50000 - . . . . . -- 0.035
Test in dict : 50000 - . . . . . -- 0.023
Test in set : 50000 - . . . . . -- 0.023
Test sort/adjacent : 50000 - . . . . . -- 0.036
Test sort/groupby : 50000 - . . . . . -- 0.134
Test sort/zip : 50000 - . . . . . -- 1.121
Test sort/izip : 50000 - . . . . . -- 0.054
Test sort/tee/izip : 50000 - . . . . . -- 0.045
Test moooeeeep : 50000 - . . . . . -- 0.019 *
Test iter*/sorted : 50000 - . . . . . -- 0.055
Test set len change : 500000 - . . . . . -- 0.249
Test in dict : 500000 - . . . . . -- 0.145
Test in set : 500000 - . . . . . -- 0.165
Test sort/adjacent : 500000 - . . . . . -- 0.139
Test sort/groupby : 500000 - . . . . . -- 1.138
Test sort/zip : 500000 - . . . . . -- 1.159
Test sort/izip : 500000 - . . . . . -- 0.126
Test sort/tee/izip : 500000 - . . . . . -- 0.120 *
Test moooeeeep : 500000 - . . . . . -- 0.131
Test iter*/sorted : 500000 - . . . . . -- 0.157
.next()
İkinci kod bloğu çağrı Python 3.x çalışmıyor Bence next(getDupes(l))
Python sürümlerinde çalışmalı, bu yüzden bunu değiştirmek mantıklı olabilir.
ifilter
ve ìzip
sadece yerleşik filter
ve zip
Python 3.x ile değiştirilebilir.
Bunu kısa ve öz bir şekilde yapmanın başka bir yolu Counter'tır .
Sadece orijinal listede herhangi bir kopya olup olmadığını belirlemek için:
from collections import Counter
def has_dupes(l):
# second element of the tuple has number of repetitions
return Counter(l).most_common()[0][1] > 1
Veya kopyaları olan öğelerin bir listesini almak için:
def get_dupes(l):
return [k for k, v in Counter(l).items() if v > 1]
Bunu en iyi performansı yapmak için buldum çünkü ilk çoğaltıldığında çalışmayı kısa devre yaptı, sonra bu algoritma zaman ve uzay karmaşıklığına sahip O (n) burada n listenin uzunluğu:
def has_duplicated_elements(iterable):
""" Given an `iterable`, return True if there are duplicated entries. """
clean_elements_set = set()
clean_elements_set_add = clean_elements_set.add
for possible_duplicate_element in iterable:
if possible_duplicate_element in clean_elements_set:
return True
else:
clean_elements_set_add( possible_duplicate_element )
return False
Daha basit bir çözüm aşağıdaki gibidir. Sadece panda .duplicated()
yöntemi ile Doğru / Yanlış kontrol edin ve sonra toplamı alın. Lütfen ayrıca pandas.Series.duplicated - pandas 0.24.1 belgelerine bakın
import pandas as pd
def has_duplicated(l):
return pd.Series(l).duplicated().sum() > 0
print(has_duplicated(['one', 'two', 'one']))
# True
print(has_duplicated(['one', 'two', 'three']))
# False
Liste paylaşılamayan öğeler içeriyorsa, Alex Martelli'nin çözümünü ancak küme yerine bir liste ile kullanabilirsiniz , ancak daha büyük girdiler için daha yavaştır: O (N ^ 2).
def has_duplicates(iterable):
seen = []
for x in iterable:
if x in seen:
return True
seen.append(x)
return False
Basitliği için pyrospade yaklaşımını kullandım ve büyük / küçük harfe duyarlı olmayan Windows kayıt defterinden kısa bir listede değiştirdim.
Ham PATH değer dizesi ayrı yollara bölünmüşse, tüm 'null' yollar (yalnızca boş veya yalnızca boşluk dizeleri) aşağıdakiler kullanılarak kaldırılabilir:
PATH_nonulls = [s for s in PATH if s.strip()]
def HasDupes(aseq) :
s = set()
return any(((x.lower() in s) or s.add(x.lower())) for x in aseq)
def GetDupes(aseq) :
s = set()
return set(x for x in aseq if ((x.lower() in s) or s.add(x.lower())))
def DelDupes(aseq) :
seen = set()
return [x for x in aseq if (x.lower() not in seen) and (not seen.add(x.lower()))]
Orijinal PATH, test amacıyla hem 'boş' girdilere hem de kopyalara sahiptir:
[list] Root paths in HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment:PATH[list] Root paths in HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment
1 C:\Python37\
2
3
4 C:\Python37\Scripts\
5 c:\python37\
6 C:\Program Files\ImageMagick-7.0.8-Q8
7 C:\Program Files (x86)\poppler\bin
8 D:\DATA\Sounds
9 C:\Program Files (x86)\GnuWin32\bin
10 C:\Program Files (x86)\Intel\iCLS Client\
11 C:\Program Files\Intel\iCLS Client\
12 D:\DATA\CCMD\FF
13 D:\DATA\CCMD
14 D:\DATA\UTIL
15 C:\
16 D:\DATA\UHELP
17 %SystemRoot%\system32
18
19
20 D:\DATA\CCMD\FF%SystemRoot%
21 D:\DATA\Sounds
22 %SystemRoot%\System32\Wbem
23 D:\DATA\CCMD\FF
24
25
26 c:\
27 %SYSTEMROOT%\System32\WindowsPowerShell\v1.0\
28
Boş yollar kaldırıldı, ancak yine de yinelenenleri var, örn., (1, 3) ve (13, 20):
[list] Null paths removed from HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment:PATH
1 C:\Python37\
2 C:\Python37\Scripts\
3 c:\python37\
4 C:\Program Files\ImageMagick-7.0.8-Q8
5 C:\Program Files (x86)\poppler\bin
6 D:\DATA\Sounds
7 C:\Program Files (x86)\GnuWin32\bin
8 C:\Program Files (x86)\Intel\iCLS Client\
9 C:\Program Files\Intel\iCLS Client\
10 D:\DATA\CCMD\FF
11 D:\DATA\CCMD
12 D:\DATA\UTIL
13 C:\
14 D:\DATA\UHELP
15 %SystemRoot%\system32
16 D:\DATA\CCMD\FF%SystemRoot%
17 D:\DATA\Sounds
18 %SystemRoot%\System32\Wbem
19 D:\DATA\CCMD\FF
20 c:\
21 %SYSTEMROOT%\System32\WindowsPowerShell\v1.0\
Ve son olarak, çiftler kaldırıldı:
[list] Massaged path list from in HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment:PATH
1 C:\Python37\
2 C:\Python37\Scripts\
3 C:\Program Files\ImageMagick-7.0.8-Q8
4 C:\Program Files (x86)\poppler\bin
5 D:\DATA\Sounds
6 C:\Program Files (x86)\GnuWin32\bin
7 C:\Program Files (x86)\Intel\iCLS Client\
8 C:\Program Files\Intel\iCLS Client\
9 D:\DATA\CCMD\FF
10 D:\DATA\CCMD
11 D:\DATA\UTIL
12 C:\
13 D:\DATA\UHELP
14 %SystemRoot%\system32
15 D:\DATA\CCMD\FF%SystemRoot%
16 %SystemRoot%\System32\Wbem
17 %SYSTEMROOT%\System32\WindowsPowerShell\v1.0\
def check_duplicates(my_list):
seen = {}
for item in my_list:
if seen.get(item):
return True
seen[item] = True
return False