ฉันจะหารายการที่ซ้ำกันในรายการ Python และสร้างรายการที่ซ้ำกันได้อย่างไร รายการมีจำนวนเต็มเท่านั้น
ฉันจะหารายการที่ซ้ำกันในรายการ Python และสร้างรายการที่ซ้ำกันได้อย่างไร รายการมีจำนวนเต็มเท่านั้น
คำตอบ:
set(a)
ในการลบซ้ำกันใช้ หากต้องการพิมพ์รายการที่ซ้ำกันมีลักษณะดังนี้:
a = [1,2,3,2,1,5,6,5,5,5]
import collections
print([item for item, count in collections.Counter(a).items() if count > 1])
## [1, 2, 5]
โปรดทราบว่าCounter
ไม่มีประสิทธิภาพโดยเฉพาะอย่างยิ่ง (การกำหนดเวลา ) และอาจ overkill ที่นี่ set
จะทำงานได้ดีขึ้น รหัสนี้คำนวณรายการองค์ประกอบที่ไม่ซ้ำกันในการสั่งซื้อแหล่งที่มา:
seen = set()
uniq = []
for x in a:
if x not in seen:
uniq.append(x)
seen.add(x)
หรือรัดกุมมากขึ้น:
seen = set()
uniq = [x for x in a if x not in seen and not seen.add(x)]
ฉันไม่แนะนำสไตล์หลังเนื่องจากไม่ชัดเจนว่าnot seen.add(x)
กำลังทำอะไรอยู่ ( add()
เมธอดset ส่งคืนเสมอNone
ดังนั้นจึงจำเป็นต้องใช้not
)
ในการคำนวณรายการองค์ประกอบที่ทำซ้ำโดยไม่มีไลบรารี:
seen = {}
dupes = []
for x in a:
if x not in seen:
seen[x] = 1
else:
if seen[x] == 1:
dupes.append(x)
seen[x] += 1
หากองค์ประกอบรายการไม่แฮชคุณไม่สามารถใช้ชุด / dicts และต้องหันไปใช้วิธีแก้ปัญหากำลังสอง (เปรียบเทียบแต่ละรายการด้วยกัน) ตัวอย่างเช่น:
a = [[1], [2], [3], [1], [5], [3]]
no_dupes = [x for n, x in enumerate(a) if x not in a[:n]]
print no_dupes # [[1], [2], [3], [5]]
dupes = [x for n, x in enumerate(a) if x in a[:n]]
print dupes # [[1], [3]]
O(n)
เพราะเพียง iterates O(1)
รายการครั้งเดียวและชุดการค้นหาเป็น
dup = []
else: dup.append(x)
print()
seen = set()
จากนั้นdupe = set(x for x in a if x in seen or seen.add(x))
>>> l = [1,2,3,4,4,5,5,6,1]
>>> set([x for x in l if l.count(x) > 1])
set([1, 4, 5])
l
ด้วยการset(l)
ลดความซับซ้อนของเวลากรณีที่เลวร้ายที่สุดเท่านั้นและด้วยเหตุนี้จึงไม่ทำอะไรเลยเพื่อจัดการกับปัญหาที่มีขนาดใหญ่ขึ้นด้วยคำตอบนี้ มันอาจจะไม่ง่ายเลยหลังจากทั้งหมด ในระยะสั้นอย่าทำเช่นนี้
คุณไม่ต้องการการนับไม่ว่าจะเห็นรายการนั้นมาก่อนหรือไม่ ปรับคำตอบสำหรับปัญหานี้แล้ว:
def list_duplicates(seq):
seen = set()
seen_add = seen.add
# adds all elements it doesn't know yet to seen and all other to seen_twice
seen_twice = set( x for x in seq if x in seen or seen_add(x) )
# turn the set into a list (as requested)
return list( seen_twice )
a = [1,2,3,2,1,5,6,5,5,5]
list_duplicates(a) # yields [1, 2, 5]
ในกรณีที่ความเร็วเป็นเรื่องต่อไปนี้เป็นเวลา
# file: test.py
import collections
def thg435(l):
return [x for x, y in collections.Counter(l).items() if y > 1]
def moooeeeep(l):
seen = set()
seen_add = seen.add
# adds all elements it doesn't know yet to seen and all other to seen_twice
seen_twice = set( x for x in l if x in seen or seen_add(x) )
# turn the set into a list (as requested)
return list( seen_twice )
def RiteshKumar(l):
return list(set([x for x in l if l.count(x) > 1]))
def JohnLaRooy(L):
seen = set()
seen2 = set()
seen_add = seen.add
seen2_add = seen2.add
for item in L:
if item in seen:
seen2_add(item)
else:
seen_add(item)
return list(seen2)
l = [1,2,3,2,1,5,6,5,5,5]*100
นี่คือผลลัพธ์: (ทำได้ดีมาก @JohnLaRooy!)
$ python -mtimeit -s 'import test' 'test.JohnLaRooy(test.l)'
10000 loops, best of 3: 74.6 usec per loop
$ python -mtimeit -s 'import test' 'test.moooeeeep(test.l)'
10000 loops, best of 3: 91.3 usec per loop
$ python -mtimeit -s 'import test' 'test.thg435(test.l)'
1000 loops, best of 3: 266 usec per loop
$ python -mtimeit -s 'import test' 'test.RiteshKumar(test.l)'
100 loops, best of 3: 8.35 msec per loop
ที่น่าสนใจนอกจากการกำหนดเวลาเองการจัดอันดับจะเปลี่ยนไปเล็กน้อยเมื่อใช้ pypy ที่น่าสนใจที่สุดวิธีการแบบ Counter-based นั้นมีประโยชน์อย่างมากจากการปรับแต่งของ pypy ในขณะที่วิธีการแคชที่ฉันแนะนำดูเหมือนจะแทบไม่มีผลกระทบเลย
$ pypy -mtimeit -s 'import test' 'test.JohnLaRooy(test.l)'
100000 loops, best of 3: 17.8 usec per loop
$ pypy -mtimeit -s 'import test' 'test.thg435(test.l)'
10000 loops, best of 3: 23 usec per loop
$ pypy -mtimeit -s 'import test' 'test.moooeeeep(test.l)'
10000 loops, best of 3: 39.3 usec per loop
เห็นได้ชัดว่าเอฟเฟกต์นี้เกี่ยวข้องกับ "ความซ้ำซ้อน" ของข้อมูลอินพุต ฉันได้ตั้งค่าl = [random.randrange(1000000) for i in xrange(10000)]
และรับผลลัพธ์เหล่านี้:
$ pypy -mtimeit -s 'import test' 'test.moooeeeep(test.l)'
1000 loops, best of 3: 495 usec per loop
$ pypy -mtimeit -s 'import test' 'test.JohnLaRooy(test.l)'
1000 loops, best of 3: 499 usec per loop
$ pypy -mtimeit -s 'import test' 'test.thg435(test.l)'
1000 loops, best of 3: 1.68 msec per loop
add
ทุกครั้งที่จำเป็นต้องมีการแทรก
pypy
ถ้าคุณมีประโยชน์และกำลังเพิ่มความเร็ว
คุณสามารถใช้iteration_utilities.duplicates
:
>>> from iteration_utilities import duplicates
>>> list(duplicates([1,1,2,1,2,3,4,2]))
[1, 1, 2, 2]
หรือหากคุณต้องการให้มีหนึ่งในสำเนาที่ซ้ำกันซึ่งสามารถรวมกับiteration_utilities.unique_everseen
:
>>> from iteration_utilities import unique_everseen
>>> list(unique_everseen(duplicates([1,1,2,1,2,3,4,2])))
[1, 2]
นอกจากนี้ยังสามารถจัดการองค์ประกอบที่ไม่สามารถล้างได้ (แต่ต้องเสียค่าใช้จ่ายที่ประสิทธิภาพ):
>>> list(duplicates([[1], [2], [1], [3], [1]]))
[[1], [1]]
>>> list(unique_everseen(duplicates([[1], [2], [1], [3], [1]])))
[[1]]
นั่นเป็นสิ่งที่มีเพียงไม่กี่วิธีที่สามารถจัดการได้
ฉันทำเกณฑ์มาตรฐานอย่างรวดเร็วซึ่งมีแนวทางที่กล่าวถึงที่นี่ (แต่ไม่ใช่ทั้งหมด)
เกณฑ์มาตรฐานแรกรวมช่วงความยาวรายการเพียงเล็กน้อยเท่านั้นเนื่องจากบางแนวทางมีO(n**2)
พฤติกรรม
ในกราฟแกน y แสดงเวลาดังนั้นค่าที่ต่ำกว่าจึงหมายถึงดีกว่า นอกจากนี้ยังมีการพล็อตล็อกบันทึกเพื่อให้สามารถมองเห็นค่าได้หลากหลาย:
การลบO(n**2)
วิธีการที่ฉันได้ทำมาตรฐานอื่น ๆ ถึงครึ่งล้านองค์ประกอบในรายการ:
คุณจะเห็นว่าiteration_utilities.duplicates
วิธีการนั้นเร็วกว่าวิธีอื่น ๆ และแม้แต่การผูกมัดunique_everseen(duplicates(...))
นั้นเร็วกว่าหรือเร็วกว่าวิธีอื่น ๆ
อีกสิ่งที่น่าสนใจเพิ่มเติมที่ควรทราบที่นี่คือวิธีการของ pandas นั้นช้ามากสำหรับรายการขนาดเล็ก
อย่างไรก็ตามเนื่องจากมาตรฐานเหล่านี้แสดงวิธีการส่วนใหญ่ที่ดำเนินการอย่างเท่าเทียมกันดังนั้นจึงไม่สำคัญว่าจะใช้วิธีใด (ยกเว้น 3 ที่O(n**2)
ใช้งานจริง)
from iteration_utilities import duplicates, unique_everseen
from collections import Counter
import pandas as pd
import itertools
def georg_counter(it):
return [item for item, count in Counter(it).items() if count > 1]
def georg_set(it):
seen = set()
uniq = []
for x in it:
if x not in seen:
uniq.append(x)
seen.add(x)
def georg_set2(it):
seen = set()
return [x for x in it if x not in seen and not seen.add(x)]
def georg_set3(it):
seen = {}
dupes = []
for x in it:
if x not in seen:
seen[x] = 1
else:
if seen[x] == 1:
dupes.append(x)
seen[x] += 1
def RiteshKumar_count(l):
return set([x for x in l if l.count(x) > 1])
def moooeeeep(seq):
seen = set()
seen_add = seen.add
# adds all elements it doesn't know yet to seen and all other to seen_twice
seen_twice = set( x for x in seq if x in seen or seen_add(x) )
# turn the set into a list (as requested)
return list( seen_twice )
def F1Rumors_implementation(c):
a, b = itertools.tee(sorted(c))
next(b, None)
r = None
for k, g in zip(a, b):
if k != g: continue
if k != r:
yield k
r = k
def F1Rumors(c):
return list(F1Rumors_implementation(c))
def Edward(a):
d = {}
for elem in a:
if elem in d:
d[elem] += 1
else:
d[elem] = 1
return [x for x, y in d.items() if y > 1]
def wordsmith(a):
return pd.Series(a)[pd.Series(a).duplicated()].values
def NikhilPrabhu(li):
li = li.copy()
for x in set(li):
li.remove(x)
return list(set(li))
def firelynx(a):
vc = pd.Series(a).value_counts()
return vc[vc > 1].index.tolist()
def HenryDev(myList):
newList = set()
for i in myList:
if myList.count(i) >= 2:
newList.add(i)
return list(newList)
def yota(number_lst):
seen_set = set()
duplicate_set = set(x for x in number_lst if x in seen_set or seen_set.add(x))
return seen_set - duplicate_set
def IgorVishnevskiy(l):
s=set(l)
d=[]
for x in l:
if x in s:
s.remove(x)
else:
d.append(x)
return d
def it_duplicates(l):
return list(duplicates(l))
def it_unique_duplicates(l):
return list(unique_everseen(duplicates(l)))
from simple_benchmark import benchmark
import random
funcs = [
georg_counter, georg_set, georg_set2, georg_set3, RiteshKumar_count, moooeeeep,
F1Rumors, Edward, wordsmith, NikhilPrabhu, firelynx,
HenryDev, yota, IgorVishnevskiy, it_duplicates, it_unique_duplicates
]
args = {2**i: [random.randint(0, 2**(i-1)) for _ in range(2**i)] for i in range(2, 12)}
b = benchmark(funcs, args, 'list size')
b.plot()
funcs = [
georg_counter, georg_set, georg_set2, georg_set3, moooeeeep,
F1Rumors, Edward, wordsmith, firelynx,
yota, IgorVishnevskiy, it_duplicates, it_unique_duplicates
]
args = {2**i: [random.randint(0, 2**(i-1)) for _ in range(2**i)] for i in range(2, 20)}
b = benchmark(funcs, args, 'list size')
b.plot()
1 นี้มาจากห้องสมุดบุคคลที่สามที่ฉันเขียน: iteration_utilities
.
ฉันเจอคำถามนี้ในขณะที่มองหาบางสิ่งที่เกี่ยวข้อง - และสงสัยว่าทำไมไม่มีใครเสนอโซลูชันที่ใช้ตัวสร้าง? การแก้ปัญหานี้จะเป็น:
>>> print list(getDupes_9([1,2,3,2,1,5,6,5,5,5]))
[1, 2, 5]
ฉันเกี่ยวข้องกับความสามารถในการปรับขนาดได้ดังนั้นทดสอบหลายวิธีรวมถึงรายการที่ไร้เดียงสาที่ทำงานได้ดีในรายการขนาดเล็ก แต่เพิ่มขนาดอย่างน่ากลัวเมื่อรายการมีขนาดใหญ่ขึ้น (หมายเหตุ - ควรใช้ timeit ดีกว่า แต่นี่เป็นตัวอย่าง)
ฉันรวม @moooeeeep เพื่อเปรียบเทียบ (มันรวดเร็วน่าประทับใจ: เร็วที่สุดถ้ารายการอินพุตเป็นแบบสุ่มทั้งหมด) และวิธีการ itertools ที่เร็วยิ่งขึ้นอีกครั้งสำหรับรายการที่เรียงลำดับส่วนใหญ่ ... ตอนนี้มีวิธีการ pandas จาก @f allnx - ช้า แต่ไม่ อย่างน่ากลัวและเรียบง่าย หมายเหตุ - วิธีการเรียงลำดับ / ทีออฟ / ซิปนั้นเร็วที่สุดในเครื่องของฉันสำหรับรายการที่สั่งซื้อจำนวนมากส่วนใหญ่ moooeeeep นั้นเร็วที่สุดสำหรับรายการที่สับแล้ว แต่ระยะทางของคุณอาจเปลี่ยนแปลง
ข้อดี
สมมติฐาน
วิธีแก้ปัญหาที่เร็วที่สุดรายการ 1m:
def getDupes(c):
'''sort/tee/izip'''
a, b = itertools.tee(sorted(c))
next(b, None)
r = None
for k, g in itertools.izip(a, b):
if k != g: continue
if k != r:
yield k
r = k
แนวทางการทดสอบ
import itertools
import time
import random
def getDupes_1(c):
'''naive'''
for i in xrange(0, len(c)):
if c[i] in c[:i]:
yield c[i]
def getDupes_2(c):
'''set len change'''
s = set()
for i in c:
l = len(s)
s.add(i)
if len(s) == l:
yield i
def getDupes_3(c):
'''in dict'''
d = {}
for i in c:
if i in d:
if d[i]:
yield i
d[i] = False
else:
d[i] = True
def getDupes_4(c):
'''in set'''
s,r = set(),set()
for i in c:
if i not in s:
s.add(i)
elif i not in r:
r.add(i)
yield i
def getDupes_5(c):
'''sort/adjacent'''
c = sorted(c)
r = None
for i in xrange(1, len(c)):
if c[i] == c[i - 1]:
if c[i] != r:
yield c[i]
r = c[i]
def getDupes_6(c):
'''sort/groupby'''
def multiple(x):
try:
x.next()
x.next()
return True
except:
return False
for k, g in itertools.ifilter(lambda x: multiple(x[1]), itertools.groupby(sorted(c))):
yield k
def getDupes_7(c):
'''sort/zip'''
c = sorted(c)
r = None
for k, g in zip(c[:-1],c[1:]):
if k == g:
if k != r:
yield k
r = k
def getDupes_8(c):
'''sort/izip'''
c = sorted(c)
r = None
for k, g in itertools.izip(c[:-1],c[1:]):
if k == g:
if k != r:
yield k
r = k
def getDupes_9(c):
'''sort/tee/izip'''
a, b = itertools.tee(sorted(c))
next(b, None)
r = None
for k, g in itertools.izip(a, b):
if k != g: continue
if k != r:
yield k
r = k
def getDupes_a(l):
'''moooeeeep'''
seen = set()
seen_add = seen.add
# adds all elements it doesn't know yet to seen and all other to seen_twice
for x in l:
if x in seen or seen_add(x):
yield x
def getDupes_b(x):
'''iter*/sorted'''
x = sorted(x)
def _matches():
for k,g in itertools.izip(x[:-1],x[1:]):
if k == g:
yield k
for k, n in itertools.groupby(_matches()):
yield k
def getDupes_c(a):
'''pandas'''
import pandas as pd
vc = pd.Series(a).value_counts()
i = vc[vc > 1].index
for _ in i:
yield _
def hasDupes(fn,c):
try:
if fn(c).next(): return True # Found a dupe
except StopIteration:
pass
return False
def getDupes(fn,c):
return list(fn(c))
STABLE = True
if STABLE:
print 'Finding FIRST then ALL duplicates, single dupe of "nth" placed element in 1m element array'
else:
print 'Finding FIRST then ALL duplicates, single dupe of "n" included in randomised 1m element array'
for location in (50,250000,500000,750000,999999):
for test in (getDupes_2, getDupes_3, getDupes_4, getDupes_5, getDupes_6,
getDupes_8, getDupes_9, getDupes_a, getDupes_b, getDupes_c):
print 'Test %-15s:%10d - '%(test.__doc__ or test.__name__,location),
deltas = []
for FIRST in (True,False):
for i in xrange(0, 5):
c = range(0,1000000)
if STABLE:
c[0] = location
else:
c.append(location)
random.shuffle(c)
start = time.time()
if FIRST:
print '.' if location == test(c).next() else '!',
else:
print '.' if [location] == list(test(c)) else '!',
deltas.append(time.time()-start)
print ' -- %0.3f '%(sum(deltas)/len(deltas)),
print
print
ผลลัพธ์สำหรับการทดสอบ 'ทุกคน' มีความสอดคล้องกันการค้นหา "ที่ซ้ำกัน" ครั้งแรกและจากนั้น "ทั้งหมด" ที่ซ้ำกันในอาร์เรย์นี้:
Finding FIRST then ALL duplicates, single dupe of "nth" placed element in 1m element array
Test set len change : 500000 - . . . . . -- 0.264 . . . . . -- 0.402
Test in dict : 500000 - . . . . . -- 0.163 . . . . . -- 0.250
Test in set : 500000 - . . . . . -- 0.163 . . . . . -- 0.249
Test sort/adjacent : 500000 - . . . . . -- 0.159 . . . . . -- 0.229
Test sort/groupby : 500000 - . . . . . -- 0.860 . . . . . -- 1.286
Test sort/izip : 500000 - . . . . . -- 0.165 . . . . . -- 0.229
Test sort/tee/izip : 500000 - . . . . . -- 0.145 . . . . . -- 0.206 *
Test moooeeeep : 500000 - . . . . . -- 0.149 . . . . . -- 0.232
Test iter*/sorted : 500000 - . . . . . -- 0.160 . . . . . -- 0.221
Test pandas : 500000 - . . . . . -- 0.493 . . . . . -- 0.499
เมื่อรายการถูกสับเป็นอันดับแรกราคาของการจัดเรียงจะปรากฏขึ้นอย่างมีประสิทธิภาพลดลงอย่างเห็นได้ชัดและวิธีการ @moooeeeep มีอำนาจเหนือกว่าด้วยวิธีการตั้งค่า & dict จะคล้ายกัน แต่มีประสิทธิภาพน้อยกว่า:
Finding FIRST then ALL duplicates, single dupe of "n" included in randomised 1m element array
Test set len change : 500000 - . . . . . -- 0.321 . . . . . -- 0.473
Test in dict : 500000 - . . . . . -- 0.285 . . . . . -- 0.360
Test in set : 500000 - . . . . . -- 0.309 . . . . . -- 0.365
Test sort/adjacent : 500000 - . . . . . -- 0.756 . . . . . -- 0.823
Test sort/groupby : 500000 - . . . . . -- 1.459 . . . . . -- 1.896
Test sort/izip : 500000 - . . . . . -- 0.786 . . . . . -- 0.845
Test sort/tee/izip : 500000 - . . . . . -- 0.743 . . . . . -- 0.804
Test moooeeeep : 500000 - . . . . . -- 0.234 . . . . . -- 0.311 *
Test iter*/sorted : 500000 - . . . . . -- 0.776 . . . . . -- 0.840
Test pandas : 500000 - . . . . . -- 0.539 . . . . . -- 0.540
random.shuffle(c)
คำนึงถึงสิ่งนั้น นอกจากนี้ฉันไม่สามารถจำลองผลลัพธ์ของคุณเมื่อรันสคริปต์ที่ไม่เปลี่ยนแปลงเช่นกัน (เรียงลำดับแตกต่างกันโดยสิ้นเชิง) ดังนั้นบางทีมันก็ขึ้นอยู่กับ CPU ด้วยเช่นกัน
ใช้แพนด้า:
>>> import pandas as pd
>>> a = [1, 2, 1, 3, 3, 3, 0]
>>> pd.Series(a)[pd.Series(a).duplicated()].values
array([1, 3, 3])
คอลเล็กชันตัวนับใหม่ใน python 2.7:
Python 2.5.4 (r254:67916, May 31 2010, 15:03:39)
[GCC 4.1.2 20080704 (Red Hat 4.1.2-46)] on linux2
a = [1,2,3,2,1,5,6,5,5,5]
import collections
print [x for x, y in collections.Counter(a).items() if y > 1]
Type "help", "copyright", "credits" or "license" for more information.
File "", line 1, in
AttributeError: 'module' object has no attribute 'Counter'
>>>
ในเวอร์ชันก่อนหน้านี้คุณสามารถใช้ dict แบบเดิมแทน:
a = [1,2,3,2,1,5,6,5,5,5]
d = {}
for elem in a:
if elem in d:
d[elem] += 1
else:
d[elem] = 1
print [x for x, y in d.items() if y > 1]
นี่เป็นวิธีที่เรียบร้อยและรัดกุม -
for x in set(li):
li.remove(x)
li = list(set(li))
โดยไม่ต้องแปลงเป็นลิสต์และอาจเป็นวิธีที่ง่ายที่สุดที่จะเป็นดังนี้ สิ่งนี้อาจเป็นประโยชน์ในระหว่างการสัมภาษณ์เมื่อพวกเขาขอไม่ให้ใช้ชุด
a=[1,2,3,3,3]
dup=[]
for each in a:
if each not in dup:
dup.append(each)
print(dup)
======= เพื่อรับ 2 รายการแยกกันซึ่งมีค่าไม่ซ้ำกันและค่าซ้ำกัน
a=[1,2,3,3,3]
uniques=[]
dups=[]
for each in a:
if each not in uniques:
uniques.append(each)
else:
dups.append(each)
print("Unique values are below:")
print(uniques)
print("Duplicate values are below:")
print(dups)
ฉันจะทำแบบนี้กับหมีแพนด้าเพราะฉันใช้แพนด้ามาก
import pandas as pd
a = [1,2,3,3,3,4,5,6,6,7]
vc = pd.Series(a).value_counts()
vc[vc > 1].index.tolist()
จะช่วยให้
[3,6]
อาจไม่มีประสิทธิภาพมาก แต่แน่ใจว่ารหัสน้อยกว่าคำตอบอื่น ๆ จำนวนมากดังนั้นฉันคิดว่าฉันจะมีส่วนร่วม
pda = pd.Series(a)
print list(pda[pda.duplicated()])
ตัวอย่างที่สามของคำตอบที่ยอมรับนั้นให้คำตอบที่ผิดพลาดและไม่พยายามให้คำตอบที่ซ้ำกัน นี่คือรุ่นที่ถูกต้อง:
number_lst = [1, 1, 2, 3, 5, ...]
seen_set = set()
duplicate_set = set(x for x in number_lst if x in seen_set or seen_set.add(x))
unique_set = seen_set - duplicate_set
วิธีการเกี่ยวกับวนรอบแต่ละองค์ประกอบในรายการโดยการตรวจสอบจำนวนของเหตุการณ์ที่เกิดขึ้นแล้วเพิ่มลงในชุดซึ่งจะพิมพ์รายการที่ซ้ำกัน หวังว่านี่จะช่วยให้ใครบางคนที่นั่น
myList = [2 ,4 , 6, 8, 4, 6, 12];
newList = set()
for i in myList:
if myList.count(i) >= 2:
newList.add(i)
print(list(newList))
## [4 , 6]
เราสามารถใช้itertools.groupby
เพื่อค้นหารายการทั้งหมดที่มี dups:
from itertools import groupby
myList = [2, 4, 6, 8, 4, 6, 12]
# when the list is sorted, groupby groups by consecutive elements which are similar
for x, y in groupby(sorted(myList)):
# list(y) returns all the occurences of item x
if len(list(y)) > 1:
print x
ผลลัพธ์จะเป็น:
4
6
dupes = [x for x, y in groupby(sorted(myList)) if len(list(y)) > 1]
ฉันเดาวิธีที่มีประสิทธิภาพที่สุดในการค้นหารายการที่ซ้ำกันในรายการคือ:
from collections import Counter
def duplicates(values):
dups = Counter(values) - Counter(set(values))
return list(dups.keys())
print(duplicates([1,2,3,6,5,2]))
มันใช้Counter
องค์ประกอบทั้งหมดและองค์ประกอบที่ไม่ซ้ำกันทั้งหมด การลบอันที่หนึ่งด้วยอันที่สองจะเป็นการลบข้อมูลที่ซ้ำกันเท่านั้น
สายไปหน่อย แต่อาจมีประโยชน์สำหรับบางคน สำหรับรายการที่ใหญ่โตฉันพบว่ามันใช้งานได้สำหรับฉัน
l=[1,2,3,5,4,1,3,1]
s=set(l)
d=[]
for x in l:
if x in s:
s.remove(x)
else:
d.append(x)
d
[1,3,1]
แสดงรายการที่ซ้ำกันทั้งหมดและรักษาลำดับ
วิธีที่ง่ายและรวดเร็วในการค้นหา dupes ด้วยการวนซ้ำหนึ่งครั้งใน Python คือ:
testList = ['red', 'blue', 'red', 'green', 'blue', 'blue']
testListDict = {}
for item in testList:
try:
testListDict[item] += 1
except:
testListDict[item] = 1
print testListDict
ผลลัพธ์จะเป็นดังนี้:
>>> print testListDict
{'blue': 3, 'green': 1, 'red': 2}
สิ่งนี้และอีกมากมายในบล็อกของฉันhttp://www.howtoprogramwithpython.com
ฉันเข้ามาช้ามากในการสนทนานี้ แม้ว่าฉันอยากจะจัดการกับปัญหานี้กับหนึ่ง liners เพราะนั่นคือเสน่ห์ของ Python หากเราต้องการได้รับสิ่งที่ซ้ำกันในรายการแยกต่างหาก (หรือคอลเลกชันใด ๆ ) ฉันขอแนะนำให้ทำดังนี้ด้านล่างเรามีรายการที่ซ้ำซึ่งเราสามารถเรียกว่า 'เป้าหมาย'
target=[1,2,3,4,4,4,3,5,6,8,4,3]
ตอนนี้ถ้าเราต้องการได้ข้อมูลที่ซ้ำกันเราสามารถใช้สายการบินเดียวดังต่อไปนี้:
duplicates=dict(set((x,target.count(x)) for x in filter(lambda rec : target.count(rec)>1,target)))
รหัสนี้จะใส่ระเบียนที่ซ้ำกันเป็นคีย์และนับเป็นค่าในพจนานุกรม 'ซ้ำ' พจนานุกรม 'ซ้ำ' จะมีลักษณะดังนี้:
{3: 3, 4: 4} #it saying 3 is repeated 3 times and 4 is 4 times
หากคุณต้องการให้ระเบียนทั้งหมดที่มีรายการซ้ำอยู่คนเดียวในรายการรหัสที่สั้นกว่าของมันก็คือ:
duplicates=filter(lambda rec : target.count(rec)>1,target)
ผลลัพธ์จะเป็น:
[3, 4, 4, 4, 3, 4, 3]
มันทำงานได้อย่างสมบูรณ์ใน python 2.7.x + เวอร์ชั่น
Python 3.8 หนึ่งซับถ้าคุณไม่สนใจที่จะเขียนอัลกอริทึมของคุณเองหรือใช้ห้องสมุด:
l = [1,2,3,2,1,5,6,5,5,5]
res = [(x, count) for x, g in groupby(sorted(l)) if (count := len(list(g))) > 1]
print(res)
พิมพ์รายการและนับ:
[(1, 2), (2, 2), (5, 4)]
groupby
รับฟังก์ชั่นการจัดกลุ่มเพื่อให้คุณสามารถกำหนดการจัดกลุ่มของคุณในวิธีที่ต่างกันและส่งคืนTuple
เขตข้อมูลเพิ่มเติมตามต้องการ
groupby
ขี้เกียจดังนั้นไม่ควรช้าเกินไป
การทดสอบอื่น ๆ แน่นอนว่าต้องทำ ...
set([x for x in l if l.count(x) > 1])
... แพงเกินไป มันเร็วกว่าประมาณ 500 เท่า (อาร์เรย์ที่ยาวกว่าจะให้ผลลัพธ์ที่ดีกว่า) เพื่อใช้วิธีสุดท้ายต่อไป:
def dups_count_dict(l):
d = {}
for item in l:
if item not in d:
d[item] = 0
d[item] += 1
result_d = {key: val for key, val in d.iteritems() if val > 1}
return result_d.keys()
เพียง 2 ลูปไม่มีl.count()
การดำเนินการที่มีราคาแพงมาก
นี่คือรหัสเพื่อเปรียบเทียบวิธีการเช่น รหัสด้านล่างนี่คือผลลัพธ์:
dups_count: 13.368s # this is a function which uses l.count()
dups_count_dict: 0.014s # this is a final best function (of the 3 functions)
dups_count_counter: 0.024s # collections.Counter
รหัสการทดสอบ:
import numpy as np
from time import time
from collections import Counter
class TimerCounter(object):
def __init__(self):
self._time_sum = 0
def start(self):
self.time = time()
def stop(self):
self._time_sum += time() - self.time
def get_time_sum(self):
return self._time_sum
def dups_count(l):
return set([x for x in l if l.count(x) > 1])
def dups_count_dict(l):
d = {}
for item in l:
if item not in d:
d[item] = 0
d[item] += 1
result_d = {key: val for key, val in d.iteritems() if val > 1}
return result_d.keys()
def dups_counter(l):
counter = Counter(l)
result_d = {key: val for key, val in counter.iteritems() if val > 1}
return result_d.keys()
def gen_array():
np.random.seed(17)
return list(np.random.randint(0, 5000, 10000))
def assert_equal_results(*results):
primary_result = results[0]
other_results = results[1:]
for other_result in other_results:
assert set(primary_result) == set(other_result) and len(primary_result) == len(other_result)
if __name__ == '__main__':
dups_count_time = TimerCounter()
dups_count_dict_time = TimerCounter()
dups_count_counter = TimerCounter()
l = gen_array()
for i in range(3):
dups_count_time.start()
result1 = dups_count(l)
dups_count_time.stop()
dups_count_dict_time.start()
result2 = dups_count_dict(l)
dups_count_dict_time.stop()
dups_count_counter.start()
result3 = dups_counter(l)
dups_count_counter.stop()
assert_equal_results(result1, result2, result3)
print 'dups_count: %.3f' % dups_count_time.get_time_sum()
print 'dups_count_dict: %.3f' % dups_count_dict_time.get_time_sum()
print 'dups_count_counter: %.3f' % dups_count_counter.get_time_sum()
วิธีที่ 1:
list(set([val for idx, val in enumerate(input_list) if val in input_list[idx+1:]]))
คำอธิบาย: [val สำหรับ idx, val ใน enumerate (input_list) ถ้า val ใน input_list [idx + 1:]] เป็นรายการความเข้าใจที่ส่งกลับองค์ประกอบหากองค์ประกอบเดียวกันมีอยู่จากตำแหน่งปัจจุบันในรายการดัชนี .
ตัวอย่าง: input_list = [42,31,42,31,3,31,31,5,6,6,6,6,6,6,6,6,7,42]
เริ่มต้นด้วยองค์ประกอบแรกในรายการ 42 กับดัชนี 0 จะตรวจสอบว่าองค์ประกอบ 42 มีอยู่ใน input_list [1:] (เช่นจากดัชนี 1 จนถึงจุดสิ้นสุดรายการ) เนื่องจาก 42 มีอยู่ใน input_list [1:] มันจะกลับ 42
จากนั้นไปที่องค์ประกอบถัดไปที่ 31 โดยมีดัชนี 1 และตรวจสอบว่าองค์ประกอบ 31 นั้นมีอยู่ใน input_list [2:] (เช่นจากดัชนี 2 จนถึงตอนท้ายของรายการ) เนื่องจาก 31 มีอยู่ใน input_list [2:] มันจะกลับ 31
มันจะผ่านองค์ประกอบทั้งหมดในรายการและจะส่งกลับองค์ประกอบที่ซ้ำกัน / ซ้ำไปยังรายการเท่านั้น
จากนั้นเนื่องจากเรามีรายการที่ซ้ำกันเราจึงต้องเลือกรายการที่ซ้ำกันหนึ่งรายการนั่นคือลบรายการที่ซ้ำกันออกจากรายการที่ซ้ำกันและเราจะเรียกชุดชื่อในตัวของหลาม () และจะลบรายการที่ซ้ำกันออก
จากนั้นเราจะเหลือชุด แต่ไม่ใช่รายการและด้วยเหตุนี้เมื่อต้องการแปลงจากชุดเป็นรายการเราใช้ typecasting, list () และแปลงชุดขององค์ประกอบเป็นรายการ
วิธีที่ 2:
def dupes(ilist):
temp_list = [] # initially, empty temporary list
dupe_list = [] # initially, empty duplicate list
for each in ilist:
if each in temp_list: # Found a Duplicate element
if not each in dupe_list: # Avoid duplicate elements in dupe_list
dupe_list.append(each) # Add duplicate element to dupe_list
else:
temp_list.append(each) # Add a new (non-duplicate) to temp_list
return dupe_list
คำอธิบาย: ที่ นี่เราสร้างสองรายการที่ว่างเปล่าเพื่อเริ่มต้นด้วย จากนั้นตรวจสอบองค์ประกอบทั้งหมดของรายการเพื่อดูว่ามีอยู่ใน temp_list (ว่างเปล่าในตอนแรก) หรือไม่ หากไม่มีอยู่ใน temp_list เราจะเพิ่มใน temp_list โดยใช้วิธีการต่อท้าย
หากมีอยู่แล้วใน temp_list ก็หมายความว่าองค์ประกอบปัจจุบันของรายการนั้นซ้ำกันและด้วยเหตุนี้เราจำเป็นต้องเพิ่มลงใน dupe_list โดยใช้วิธีการต่อท้าย
raw_list = [1,2,3,3,4,5,6,6,7,2,3,4,2,3,4,1,3,4,]
clean_list = list(set(raw_list))
duplicated_items = []
for item in raw_list:
try:
clean_list.remove(item)
except ValueError:
duplicated_items.append(item)
print(duplicated_items)
# [3, 6, 2, 3, 4, 2, 3, 4, 1, 3, 4]
คุณพื้นลบรายการที่ซ้ำโดยการแปลงชุด ( clean_list
) แล้วย้ำraw_list
ในขณะที่แต่ละลบในรายการที่สะอาดสำหรับการเกิดขึ้นในitem
raw_list
หากitem
ไม่พบValueError
ข้อยกเว้นที่ยกขึ้นจะถูกจับและitem
เพิ่มลงในduplicated_items
รายการ
หากต้องการดัชนีของรายการที่ซ้ำกันเพียงenumerate
รายการและเล่นกับดัชนี ( for index, item in enumerate(raw_list):
) ซึ่งเร็วกว่าและปรับให้เหมาะสมสำหรับรายการขนาดใหญ่ (เช่นองค์ประกอบหลายพันรายการ)
ใช้list.count()
วิธีการในรายการเพื่อค้นหาองค์ประกอบที่ซ้ำกันของรายการที่กำหนด
arr=[]
dup =[]
for i in range(int(input("Enter range of list: "))):
arr.append(int(input("Enter Element in a list: ")))
for i in arr:
if arr.count(i)>1 and i not in dup:
dup.append(i)
print(dup)
หนึ่งซับเพื่อความสนุกสนานและในกรณีที่จำเป็นต้องมีคำสั่งเดียว
(lambda iterable: reduce(lambda (uniq, dup), item: (uniq, dup | {item}) if item in uniq else (uniq | {item}, dup), iterable, (set(), set())))(some_iterable)
list2 = [1, 2, 3, 4, 1, 2, 3]
lset = set()
[(lset.add(item), list2.append(item))
for item in list2 if item not in lset]
print list(lset)
โซลูชันเดียว:
set([i for i in list if sum([1 for a in list if a == i]) > 1])
มีคำตอบมากมายที่นี่ แต่ฉันคิดว่านี่เป็นวิธีที่อ่านได้ง่ายและเข้าใจได้ง่ายมาก:
def get_duplicates(sorted_list):
duplicates = []
last = sorted_list[0]
for x in sorted_list[1:]:
if x == last:
duplicates.append(x)
last = x
return set(duplicates)
หมายเหตุ:
ต่อไปนี้เป็นตัวสร้างที่รวดเร็วซึ่งใช้ dict เพื่อจัดเก็บองค์ประกอบแต่ละรายการเป็นคีย์ที่มีค่าบูลีนสำหรับตรวจสอบว่ารายการที่ซ้ำกันได้รับผลไปแล้ว
สำหรับรายการที่มีองค์ประกอบทั้งหมดที่เป็นประเภทแฮช:
def gen_dupes(array):
unique = {}
for value in array:
if value in unique and unique[value]:
unique[value] = False
yield value
else:
unique[value] = True
array = [1, 2, 2, 3, 4, 1, 5, 2, 6, 6]
print(list(gen_dupes(array)))
# => [2, 1, 6]
สำหรับรายการที่อาจมีรายการ:
def gen_dupes(array):
unique = {}
for value in array:
is_list = False
if type(value) is list:
value = tuple(value)
is_list = True
if value in unique and unique[value]:
unique[value] = False
if is_list:
value = list(value)
yield value
else:
unique[value] = True
array = [1, 2, 2, [1, 2], 3, 4, [1, 2], 5, 2, 6, 6]
print(list(gen_dupes(array)))
# => [2, [1, 2], 6]
def removeduplicates(a):
seen = set()
for i in a:
if i not in seen:
seen.add(i)
return seen
print(removeduplicates([1,1,2,2]))
เมื่อใช้toolz :
from toolz import frequencies, valfilter
a = [1,2,2,3,4,5,4]
>>> list(valfilter(lambda count: count > 1, frequencies(a)).keys())
[2,4]
นี่คือวิธีที่ฉันต้องทำเพราะฉันท้าทายตัวเองไม่ให้ใช้วิธีอื่น:
def dupList(oldlist):
if type(oldlist)==type((2,2)):
oldlist=[x for x in oldlist]
newList=[]
newList=newList+oldlist
oldlist=oldlist
forbidden=[]
checkPoint=0
for i in range(len(oldlist)):
#print 'start i', i
if i in forbidden:
continue
else:
for j in range(len(oldlist)):
#print 'start j', j
if j in forbidden:
continue
else:
#print 'after Else'
if i!=j:
#print 'i,j', i,j
#print oldlist
#print newList
if oldlist[j]==oldlist[i]:
#print 'oldlist[i],oldlist[j]', oldlist[i],oldlist[j]
forbidden.append(j)
#print 'forbidden', forbidden
del newList[j-checkPoint]
#print newList
checkPoint=checkPoint+1
return newList
ตัวอย่างของคุณทำงานเป็น:
>>>a = [1,2,3,3,3,4,5,6,6,7]
>>>dupList(a)
[1, 2, 3, 4, 5, 6, 7]
duplist = list(set(a))
ที่จะทำให้รายการที่มีรายการที่ซ้ำกันออกผมจะแนะนำ