前一段时间遇到过一个问题,它让我想知道最好的方法是什么。
想要一个接受输入字符串并返回布尔值的方法,无论给定的字符串是否只有1个字符重复(可以重复多次)
即:' abca' - >是的,' abab' - >错,' aaaa' - >真
我的解决方案似乎有点复杂,我想知道更好的方法
#!/usr/bin/env python
import collections
def hasOnlyOneDuplicate(string):
# turn string into a dictionary with counter and obtain a list of all the values/occurences of each letter
values = list(collections.Counter(string).values())
# then we remove all the numbers that are a 1
result = filter(lambda a: a!=1, values)
return len(result) == 1
如果给定字符串中只有1个重复字符,则剩余列表的长度应为1,对吗?否则有多个字符重复
感谢您的帮助
答案 0 :(得分:2)
使用set
可以轻松完成此操作。我正在使用您的示例'abca'
def hasOnlyOneDuplicate(s):
return len(set(a for a in s if s.count(a) > 1))==1
答案 1 :(得分:2)
另一种使用str.count()
和短路欺骗计数器的方法:
def hasOnlyOneDuplicate(s):
nDupes = 0
for ch in set(s):
if s.count(ch) > 1:
nDupes += 1
if nDupes > 1:
return False
return (nDupes == 1)
<强>更新强>
此解决方案是最快的,特别是对于长字长度:
from collections import Counter
import string
import random
def hasOnlyOneDuplicate_pault(s):
nDupes = 0
for ch in set(s):
if s.count(ch) > 1:
nDupes += 1
if nDupes > 1:
return False
return (nDupes == 1)
def hasOnlyOneDuplicate_dev(s):
x = list(s)
if len(set([a for a in x if x.count(a) > 1]))==1:
return True
else:
return False
def hasOnlyOneDuplicate_john(s):
return len([c for c,v in Counter(s).items() if v > 1]) == 1
N = 1000
test_words = [
''.join(random.choice(string.lowercase) for _ in range(random.randint(3,30)))
for _ in range(N)
]
%%timeit
len([hasOnlyOneDuplicate_pault(s) for s in test_words])
# 100 loops, best of 3: 2.57 ms per loop
%%timeit
len([hasOnlyOneDuplicate_dev(s) for s in test_words])
# 100 loops, best of 3: 7.6 ms per loop
%%timeit
len([hasOnlyOneDuplicate_john(s) for s in test_words])
# 100 loops, best of 3: 9.61 ms per loop
更新2
所有发布的答案都比OP的解决方案更快:
%%timeit
len([hasOnlyOneDuplicate(s) for s in test_words])
# 100 loops, best of 3: 10.9 ms per loop
答案 2 :(得分:1)
这是另一种方式:
from collections import Counter
def hasOnlyOneDuplicate(s):
return len([c for c,v in Counter(s).items() if v > 1]) == 1
使用理解而不是filter
和lambda
更具有pythonic。