эффективно проверить, что строка состоит из одного символа в Python
каков эффективный способ проверить, что строка s в Python состоит всего из одного символа, скажем 'A'? Что-то вроде all_equal(s, 'A') что будет вести себя так:
all_equal("AAAAA", "A") = True
all_equal("AAAAAAAAAAA", "A") = True
all_equal("AAAAAfAAAAA", "A") = False
два, казалось бы, неэффективных способа: во-первых, преобразовать строку в список и проверить каждый элемент, или во-вторых, использовать регулярное выражение. Существуют ли более эффективные способы или это лучшее, что можно сделать в Python? Спасибо.
8 ответов:
это самый быстрый, в несколько раз быстрее, чем даже
count(), просто время это с тем, что отлично набор времени мгилсона:s == len(s) * s[0]здесь вся проверка выполняется внутри кода Python C, который просто:
- выделяет символы len(s);
- заполняет пробел первым символом;
- сравнивает две строки.
чем длиннее строка, тем больше бонусного времени. Однако, как mgilson пишет, он создает копию строки, поэтому, если ваша длина строки составляет много миллионов символов, это может стать проблемой.
как мы видим из результатов синхронизации, как правило, самые быстрые способы решения задачи не выполняют никакого кода Python для каждого символа. Тем не менее,
set()решение также выполняет всю работу внутри кода C библиотеки Python, но оно все еще медленное, вероятно, из-за операционной строки через интерфейс объекта Python.UPD: Относительно пустого строкового случая. Что с ним делать сильно зависит от поставленной задачи. Если задача "проверить, все ли символы в строке одинаковы",
s == len(s) * s[0]является допустимым ответом (нет символов означает ошибку, и исключение в порядке). Если задача "проверить, есть ли ровно один уникальный символ", пустая строка должна дать нам False, и ответs and s == len(s) * s[0]илиbool(s) and s == len(s) * s[0]если вы предпочитаете получать логические значения. Наконец, если мы понимаем задачу как "проверить, нет ли разных символов", результат для пустой строки верно, и ответnot s or s == len(s) * s[0].
>>> s = 'AAAAAAAAAAAAAAAAAAA' >>> s.count(s[0]) == len(s) Trueэто не короткое замыкание. Версия, которая делает короткое замыкание будет:
>>> all(x == s[0] for x in s) Trueоднако у меня есть ощущение, что из-за оптимизированной реализации C, версия без короткого замыкания, вероятно, будет работать лучше на некоторых строках (в зависимости от размера и т. д.)
вот простой
timeitскрипт для проверки некоторых других параметров, опубликованных:import timeit import re def test_regex(s,regex=re.compile(r'^(.)*$')): 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на моей машине (OS-X 10.5.8, core2duo, python2. 7. 3) с этими надуманные (короткие) строки,
str.countкуритsetиall, и бьет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тайминги могут быть немного (или даже значительно?) разные между разными системами и с разными строками, так что это стоило бы изучить с фактической строкой, которую вы планируете передать.
в конце концов, если вы попали в лучшем случае на
allдостаточно, и ваши строки достаточно длинные, вы можете рассмотреть этот вопрос. Это лучший алгоритм ... Я бы избегалsetрешение, хотя, как я не вижу ни одного случая, когда он мог бы выбитьcountрешение.если память может быть проблемой, вам нужно будет избегать
str.translate,str.replaceиstrmulпоскольку они создают вторую строку, но это обычно не вызывает беспокойства в эти дни.
попробуйте использовать встроенную функцию
all:all(c == 'A' for c in s)
Если вам нужно проверить, все ли символы в строке одинаковы и равны заданному символу, вам нужно удалить все дубликаты и проверить, равен ли конечный результат одному символу.
>>> set("AAAAA") == set("A") Trueв случае, если вы хотите найти, если есть какие-либо дубликаты, просто проверьте длину
>>> len(set("AAAAA")) == 1 True
интересные ответы до сих пор. Вот еще:
flag = True for c in 'AAAAAAAfAAAA': if not c == 'A': flag = False breakединственное преимущество, которое я могу придумать для себя, заключается в том, что ему не нужно пересекать всю строку, если он находит непоследовательный символ.
Comments