You can use collections.Counter
:
>>> from collections import Counter
>>> [i for i,j in Counter(a).items() if j>1]
['4', '8']
Or you can use a custom function :
>>> def finder(s):
... seen,yields=set(),set()
... for i in s:
... if i in seen:
... if i not in yields:
... yield i
... yields.add(i)
... else :
... yields.add(i)
... else:
... seen.add(i)
...
>>> list(finder(a))
['4', '8']
Or use str.count
method in a set comprehension :
>>> set(i for i in a if a.count(i)>1)
set(['8', '4'])
A benchmark on all approaches, which shows that the last 2 way (custom function and set comprehensions are much faster than Counter
):
from timeit import timeit
s1="""
a = "12348546478"
[i for i,j in Counter(a).items() if j>1]
"""
s2="""
def finder(s):
seen,yields=set(),set()
for i in s:
if i in seen:
if i not in yields:
yield i
yields.add(i)
else :
yields.add(i)
else:
seen.add(i)
a = "12348546478"
list(finder(a))
"""
s3="""
a = "12348546478"
set(i for i in a if a.count(i)>1)
"""
print '1st: ' ,timeit(stmt=s1, number=100000,setup="from collections import Counter")
print '2nd : ',timeit(stmt=s2, number=100000)
print '3rd : ',timeit(stmt=s2, number=100000)
result :
1st: 0.726881027222
2nd : 0.265578985214
3rd : 0.26243185997
I also tried this for long string (a = "12348546478"*10000
) and still got the same result:
1st: 25.5780302721341
2nd : 11.8482989001177
3rd : 11.926538944245
Any way my suggestion is using the set comprehension which is more pythonic :
set(i for i in a if a.count(i)>1)