有效地检查该字符串是否包含Python中的一个字符

62 python string

检查sPython 中的字符串只包含一个字符的有效方法是什么'A'?像all_equal(s, 'A')这样的东西会像这样:

all_equal("AAAAA", "A") = True

all_equal("AAAAAAAAAAA", "A") = True

all_equal("AAAAAfAAAAA", "A") = False
Run Code Online (Sandbox Code Playgroud)

两种看似效率低下的方法是:首先将字符串转换为列表并检查每个元素,然后再使用正则表达式.是否有更有效的方法,或者这些是Python中最好的方法?谢谢.

Ell*_*ioh 113

这是迄今为止最快的,比偶数快几倍count(),只是时间与优秀的mgilson定时套件:

s == len(s) * s[0]
Run Code Online (Sandbox Code Playgroud)

这里所有的检查都是在Python C代码中完成的,它只是:

  • 分配len(s)字符;
  • 用第一个字符填充空间;
  • 比较两个字符串.

字符串越长,时间奖励越大.但是,正如mgilson所写,它会创建一个字符串的副本,所以如果你的字符串长度是数百万个符号,它可能会成为一个问题.

正如我们从时序结果中看到的,通常,解决任务的最快方法不会为每个符号执行任何Python代码.但是,该set()解决方案还完成了Python库C代码中的所有工作,但它仍然很慢,可能是因为通过Python对象接口操作字符串.

UPD:关于空字符串案例.如何处理它在很大程度上取决于任务.如果任务是"检查字符串中的所有符号是否相同",s == len(s) * s[0]则是有效答案(没有符号表示错误,异常正常).如果任务是"检查是否只有一个唯一符号",则空字符串应该给我们False,答案是s and s == len(s) * s[0],或者bool(s) and s == len(s) * s[0]如果您更喜欢接收布尔值.最后,如果我们将任务理解为"检查是否没有不同的符号",则空字符串的结果为True,答案为not s or s == len(s) * s[0].

  • 如果s是空字符串怎么办? (2认同)
  • 作为一名数学家,我的直觉是如果s是空字符串,函数应该返回True.但OP应该真的表明. (2认同)

mgi*_*son 42

>>> s = 'AAAAAAAAAAAAAAAAAAA'
>>> s.count(s[0]) == len(s)
True
Run Code Online (Sandbox Code Playgroud)

这不会短路.一个做短路的版本是:

>>> all(x == s[0] for x in s)
True
Run Code Online (Sandbox Code Playgroud)

但是,我觉得由于优化的C实现,非短路版本可能在某些字符串上表现更好(取决于大小等)


这是一个简单的timeit脚本来测试发布的其他一些选项:

import timeit
import re

def test_regex(s,regex=re.compile(r'^(.)\1*$')):
    return bool(regex.match(s))

def test_all(s):
    return all(x == s[0] for x in s)

def test_count(s):
    return s.count(s[0]) == len(s)

def test_set(s):
    return len(set(s)) == 1

def test_replace(s):
    return not s.replace(s[0],'')

def test_translate(s):
    return not s.translate(None,s[0])

def test_strmul(s):
    return s == s[0]*len(s)

tests = ('test_all','test_count','test_set','test_replace','test_translate','test_strmul','test_regex')

print "WITH ALL EQUAL"
for test in tests:
    print test, timeit.timeit('%s(s)'%test,'from __main__ import %s; s="AAAAAAAAAAAAAAAAA"'%test)
    if globals()[test]("AAAAAAAAAAAAAAAAA") != True:
        print globals()[test]("AAAAAAAAAAAAAAAAA")
        raise AssertionError

print
print "WITH FIRST NON-EQUAL"
for test in tests:
    print test, timeit.timeit('%s(s)'%test,'from __main__ import %s; s="FAAAAAAAAAAAAAAAA"'%test)
    if globals()[test]("FAAAAAAAAAAAAAAAA") != False:
        print globals()[test]("FAAAAAAAAAAAAAAAA")
        raise AssertionError
Run Code Online (Sandbox Code Playgroud)

在我的机器(OS-X 10.5.8,酷睿2,python2.7.3)与这些做作(短)的字符串,str.count吸烟setall,和节拍str.replace受了一点,但被排挤出去str.translate,并strmul是目前在由佳缘的铅:

WITH ALL EQUAL
test_all 5.83863711357
test_count 0.947771072388
test_set 2.01028490067
test_replace 1.24682998657
test_translate 0.941282987595
test_strmul 0.629556179047
test_regex 2.52913498878

WITH FIRST NON-EQUAL
test_all 2.41147494316
test_count 0.942595005035
test_set 2.00480484962
test_replace 0.960338115692
test_translate 0.924381017685
test_strmul 0.622269153595
test_regex 1.36632800102
Run Code Online (Sandbox Code Playgroud)

不同系统和不同字符串之间的时间可能略有差异(甚至显着不同),因此值得研究一下您计划传递的实际字符串.

最终,如果你all足够了,并且你的字符串足够长,你可能想要考虑那个.这是一个更好的算法...我会避免set解决方案,因为我没有看到任何情况下它可能会击败count解决方案.

如果内存可能是一个问题,你需要避免str.translate,str.replace并且strmul因为那些创建了第二个字符串,但这些日子通常不是问题.


Dan*_*man 16

你可以转换成一个集合并检查只有一个成员:

len(set("AAAAAAAA"))
Run Code Online (Sandbox Code Playgroud)


Mar*_*ers 12

尝试使用内置函数all:

all(c == 'A' for c in s)
Run Code Online (Sandbox Code Playgroud)

  • 我不认为`是'可以保证工作.它依赖于解释器的实现细节,即字符串的实习,据我记忆,这根据Python规范无法保证.是的它至少可以在任何地方使用,但是"可能"并不是最好的依赖. (11认同)

Abh*_*jit 6

为此问题添加另一种解决方案

>>> not "AAAAAA".translate(None,"A")
True
Run Code Online (Sandbox Code Playgroud)


Abh*_*jit 5

如果需要检查字符串中的所有字符是否相同并且是否等于给定字符,则需要删除所有重复项并检查最终结果是否等于单个字符.

>>> set("AAAAA") == set("A")
True
Run Code Online (Sandbox Code Playgroud)

如果您想查找是否有重复,只需检查长度

>>> len(set("AAAAA")) == 1
True
Run Code Online (Sandbox Code Playgroud)