从字符串中删除重复字符

71
如何使用Python从字符串中删除重复的字符?例如,假设我有一个字符串:
foo = 'mppmt'

如何使字符串变成:

foo = 'mpt'

注意:顺序不重要。


4
咳咳... http://stackoverflow.com/questions/636977/best-way-to-remove-duplicate-characters-words-in-a-string - nullpotent
2
@AljoshaBre - 使用“关闭”按钮并选择“标记为重复项”,然后提供该链接。谢谢。 - Martin Beckett
3
这些答案都不能保证维持秩序。 - Marcin
链接实际上已经存在。只需要4个点击即可。 - ulidtko
16个回答

150

如果顺序不重要,你可以使用

"".join(set(foo))

set()会创建一个字符串中唯一字母的集合,而"".join()将这些字母以任意顺序拼接回字符串。

如果顺序很重要,可以使用dict代替set。从Python 3.7开始,字典保留键的插入顺序(在CPython实现中,这在Python 3.6中已作为实现细节支持)。

foo = "mppmt"
result = "".join(dict.fromkeys(foo))

结果为字符串"mpt"。在早期版本的Python中,您可以使用collections.OrderedDict,该模块从Python 2.7开始提供。


2
“fromkeys()” 并不经常使用,但您在这里充分利用了它。 - Eric O. Lebigot
打印 "".join(OrderedDict.fromkeys(foo))
^ 语法错误:无效的语法
- flik
@flik 是的,如注释所述,上面的代码是针对 Python 2.7 版本的。 - Sven Marnach
这太棒了。非常感谢 :D - Sreekiran A R

46

如果顺序重要性,那么可以考虑这样:

>>> foo = 'mppmt'
>>> ''.join(sorted(set(foo), key=foo.index))
'mpt'

2
足够正确。但对于五个字符的字符串,它比OrderedDict.fromkeys快近8倍。;-) <闪避> - DSM
5
通常只有字符串很长时,速度才是重要的。但是我必须更正 O(n^2) 的分析。在 Python 2.x 中,集合最多只能有 256 个元素,而与字符串长度无关。考虑到这一点,时间复杂度为 O(n)。即使对于非常长的字符串,它也不会变得非常糟糕(尽管可以构造出比“OrderedDict”方法慢8倍的情况)。 - Sven Marnach
@Sven Marnach:嗯,我甚至没有考虑过字符集限制。 - DSM
“Order matters” 意味着顺序必须被保留,而不是排序。因此,“abzyxaabbx” 应该返回 “abxyx”。 - Ken Haley

13

如果顺序不重要:

>>> foo='mppmt'
>>> ''.join(set(foo))
'pmt'
为了保持顺序:
>>> foo='mppmt'
>>> ''.join([j for i,j in enumerate(foo) if j not in foo[:i]])
'mpt'

6

在Python中创建一个列表和一个不允许重复项的集合。

解决方案1:

def fix(string):
    s = set()
    list = []
    for ch in string:
        if ch not in s:
            s.add(ch)
            list.append(ch)
    
    return ''.join(list)        

string = "Protiijaayiiii"
print(fix(string))

方法二:

s = "Protijayi"

aa = [ ch  for i, ch in enumerate(s) if ch not in s[:i]]
print(''.join(aa))

方法三:

dd = ''.join(dict.fromkeys(a))
print(dd)

3

正如所提到的那样,可以使用 "".join(set(foo)) 和 collections.OrderedDict 来实现。如果字符串有大写和小写字符并且您需要删除所有重复项,无论它们是大写还是小写字符,请添加 foo = foo.lower()。

from collections import OrderedDict
foo = "EugeneEhGhsnaWW"
foo = foo.lower()
print "".join(OrderedDict.fromkeys(foo))

打印 eugnhsaw


3
#Check code and apply in your Program:

#Input= 'pppmm'    
s = 'ppppmm'
s = ''.join(set(s))  
print(s)
#Output: pm

2
不知道你是否注意到了,但你的解决方案对于OP提出的情况并不适用。 - Nik O'Lai
@NikO'Lai,感谢您指出这一点。已更改代码。 早期的代码是- pattern=reg.compile(r"(.)\1{1,}",reg.DOTALL) string=pattern.sub(r"\1",s) print(string) - hp_elite

2
如果顺序很重要,
seen = set()
result = []
for c in foo:
    if c not in seen:
        result.append(c)
        seen.add(c)
result = ''.join(result)

或者不使用集合来完成:

result = []
for c in foo:
    if c not in result:
        result.append(c)
result = ''.join(result)

1
@Marcin:我完全不理解。c 不总是在 set(foo) 中吗? - DSM
@Marcin 这将始终返回一个空字符串。foo中的每个c都在set(foo)中。 - Kevin Coffey
1
@DSM / Kevin。好在我没有将那个作为答案发布。seen = set(); ''.join(seen.add(c) or c for c in foo if c not in seen)。今天是隐式胜于显式的星期五。 - Marcin
1
像这样构建字符串 result += c 是不符合 Python 风格的,因为它每次都会创建新的字符串。 - Steven Rumbalski
不要使用字符串进行 result+=c 操作。字符串是不可变的,每次添加字符都需要创建和销毁字符串。 - the wolf

2

使用正则表达式:

import re
pattern = r'(.)\1+' # (.) any character repeated (\+) more than
repl = r'\1'        # replace it once
text = 'shhhhh!!!
re.sub(pattern,repl,text)

输出:

sh!

2
def dupe(str1):
    s=set(str1)

    return "".join(s)
str1='geeksforgeeks'
a=dupe(str1)
print(a)

如果顺序不重要,那么它的效果很好。


2
d = {}
s="YOUR_DESIRED_STRING"
res=[]
for c in s:
    if c not in d:
      res.append(c)
      d[c]=1
print ("".join(res))

在for循环中,变量'c'遍历字符串's',并检查c是否在集合d中(该集合最初没有元素)。如果c不在d中,则将c附加到字符数组'res',然后将集合d的索引c更改为1。循环结束后,即c完成遍历整个字符串以在集合d中存储唯一元素,打印所有唯一字符的结果'res'。


2
考虑加入代码描述以帮助他人理解。 - Henry Woody

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接