Использует `str` правильную идиому для работы с цифрами в Python

Я понимаю, что одним из способов работы с цифрами числа в Python является преобразование числа в строку, а затем использование строковых методов для срезания полученного «числа» в группы «цифр». Например, если предположить, что у меня есть функция prime которая проверяет примитивность, я могу подтвердить, что целое число n является как левым, так и правым truncatable prime с

 all(prime(int(str(n)[:-i])) and prime(int(str(n)[i:])) for i in range(1, len(str(n)))) 

Этот метод включает в себя сначала преобразование n в строку, чтобы его можно было нарезать и преобразовать этот срез обратно в целое число, чтобы можно было проверить его примитивность. Возможно, это моя история со статически типизированными языками или какая-то неопределенная идея о том, что строки являются «дорогими» или опыт работы с языками, которые включают встроенные функции для подобных манипуляций (например , IntegerDigits и FromDigits ); но мне осталось интересно, правильно ли это решать такие задачи.

Является ли конвертация между укусами и цифрами правильной или даже единственной возможностью доступа к цифрам в Python. Существуют ли более эффективные подходы?

    Это всегда был мой подход, и он отлично работает, хотя я никогда не делал много испытаний на скорость. Он работает особенно хорошо, когда требуется перебирать перестановки / комбинации цифр, так как вы можете создавать такие строки с функциями в пакете itertools .

    Есть, конечно, другие методы, которые включают в себя менее простые математические операции, но если скорость абсолютно невелика, я чувствую, что строковый метод является самым Pythonic.


    Вот, например, более математический подход, где a и b индексируются справа (т. Е. Одно место равно 0, десятки – 1 и т. Д.):

     def getSubdigits(n, a, b): n %= 10 ** a n //= 10 ** b return n 

    Чтобы это работало с тем же индексированием, что и строковое нарезка, вам нужно сначала найти общее количество цифр, а функция станет:

     def getSubdigits2(n, a, b): l = int(math.ceil(math.log10(n))) n %= 10 ** (l - a) n //= 10 ** (l - b) return n 

    И эквивалент строки:

     def subDigits3(n, a, b): return int(str(n)[a:n]) 

    Вот результаты синхронизации:

    • subDigits : 0.293327726114
    • subDigits2 : 0.850861833337
    • subDigits3 : 0.990543234267

    Мой взнос от этого результата заключается в том, что метод нарезки прекрасен, если вы действительно не заботитесь о скорости, и в этом случае вам нужно использовать первый метод и подумать об индексах в другом направлении.

    В вашем примере кода вы можете уйти, используя divmod а не строку, divmod цифры. divmod(x, y) возвращает кортеж x//y, x%y , который для значений x//y, x%y , divmod(x, y) 10**i является именно тем, что вы хотите для левой и правой частей вашего номера. Это не обязательно больше Pythonic, хотя это может быть немного быстрее.

     sn = str(n) all(prime(int(sn[:i])) and prime(int(sn[i:])) for i in range(1, len(sn))) # original all(all(map(prime, divmod(n, 10**i))) for i in range(1, len(sn))) # variant using divmod 

    Я думаю, что для более общих операций с цифрами использование str , вероятно, довольно разумно, так как выполнение множества математических функций по численной базе данных, вероятно, будет сложнее понять, чем делать вещи непосредственно на цифрах в строке.

    Напишите код для чтения, если он не чувствителен к производительности.

    Нативные целые числа Python хранятся в базе с мощностью-2, поэтому для преобразования их в десятичную или десятичную нотацию требуется реальная работа. Во многих типах «головоломок»; -) проблем, которые требуют частого доступа к десятичным разрядам очень больших целых чисел, он может сделать мир различий, чтобы вместо этого использовать decimal модуль. Это сохраняет значения в базе с мощностью -10, так что «преобразование» в / из десятичных цифр является тривиальным расходом.

     >>> import decimal >>> x = decimal.Decimal('1e20') - 1 >>> x Decimal('99999999999999999999') >>> x.as_tuple().digits (9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9) 

    Это занимает время, линейное по количеству цифр. Преобразование собственного целого числа в / из десятичного числа занимает квадратичное время в количестве цифр.

    Лучше всего я могу догадаться о вашем конкретном приложении здесь, хотя использование divmod() – действительно лучший подход.

    Как насчет этого?

     def digits(n): if n == 0: yield 0 else: while n: yield n % 10 n //= 10 for digit in digits(123): # do something with digit 

    Это должно быть как более удобным, так и более эффективным, чем пример, который вы показали.

    EDIT: Я хочу добавить еще две вещи.

    0) Вы можете расширить технику по мере необходимости. Предположим, вы хотите проверить правильные штрихи. Предполагая, что у вас есть функция is_prime() :

     def right_trunc_int_values(n): if n == 0: yield 0 else: while n: yield n n //= 10 assert(all(is_prime(n) for n in right_trunc_int_values(317)) 

    1) Чтобы решить общую проблему удобной работы с цифрами, вы можете использовать decimal модуль. Я рассмотрю это больше. Но между тем, вы можете использовать функцию digits() чтобы сделать индексный список цифр:

     d = list(digits(123)) print(d[2]) # prints 2 

    EDIT: довольно легко преобразовать ряд цифр в целочисленное значение.

     def int_from_digits(digits): result = 0 found_a_digit = False for digit in reversed(digits): result = result * 10 + digit return result def is_right_trunc_prime(n): d = list(digits(n)) return all(is_prime(int_from_digits(d[:i]) for i in range(len(d), -1, -1))) # example from question of left and right truncatable check d = list(digits(n)) all(prime(int_from_digits(d[:-i])) and prime(int_from_digits(d[i:])) for i in range(1, len(d))) 

    Тестирование левых truncatable простых чисел без str() и нарезки:

     def is_prime(n): if n < 2: return False elif n == 2: return True elif n % 2 == 0: return False return all(n % x for x in xrange(3,int(pow(n,0.5))+1,2)) def is_left_truncatable_prime(n): largest_power_of_ten = 1 while largest_power_of_ten < n: largest_power_of_ten *= 10 while True: largest_power_of_ten /= 10 # Use // in Python 3 if is_prime(n): n %= largest_power_of_ten if n == 0: return True else: return False print is_left_truncatable_prime(167) # True print is_left_truncatable_prime(173) # True print is_left_truncatable_prime(171) # False 

    Я не очень тщательно проверял это так жаль, если есть какие-то ошибки. Дайте мне знать, если есть, и я их исправлю.

    EDIT: немного изменил код.