Python элегантная обратная функция int (строка, база)
python позволяет конвертировать из строки в целое число с использованием любой базы в диапазоне [2,36], используя:
int(string,base)
im ищет элегантную обратную функцию, которая принимает целое число и базу и возвращает строку
например
>>> str_base(224,15)
'ee'
i имеет следующее решение:
def digit_to_char(digit):
if digit < 10: return chr(ord('0') + digit)
else: return chr(ord('a') + digit - 10)
def str_base(number,base):
if number < 0:
return '-' + str_base(-number,base)
else:
(d,m) = divmod(number,base)
if d:
return str_base(d,base) + digit_to_char(m)
else:
return digit_to_char(m)
note: digit_to_char() работает для баз данных <= 169 произвольно с использованием символов ascii после "z" в качестве цифр для оснований выше 36
существует ли встроенная функция python, библиотечная функция или более элегантная обратная функция int (string, base)?
Ответы
Ответ 1
В этом потоке есть некоторые примеры реализации.
На самом деле, я считаю, что ваше решение выглядит довольно красиво, оно даже рекурсивное, что здесь приятно.
Я бы все же упростил его, чтобы удалить else
, но это, вероятно, личный стиль. Я думаю, что if foo: return
очень ясен и не нуждается в else
после него, чтобы он очистил его отдельную ветвь.
def digit_to_char(digit):
if digit < 10:
return str(digit)
return chr(ord('a') + digit - 10)
def str_base(number,base):
if number < 0:
return '-' + str_base(-number, base)
(d, m) = divmod(number, base)
if d > 0:
return str_base(d, base) + digit_to_char(m)
return digit_to_char(m)
Я упростил случай 0-9 в digit_to_char()
, я думаю, str()
более ясен, чем конструктор chr(ord())
. Чтобы максимизировать симметрию с тегом >= 10
, а ord()
можно было бы учесть, но я не беспокоился, так как это добавило бы строку, и краткость почувствовала себя лучше.:)
Ответ 2
Возможно, это не должно быть ответом, но это может быть полезно для некоторых: встроенная функция format
выполняет преобразование чисел для строки в нескольких базах:
>>> format(255, 'b') # base 2
'11111111'
>>> format(255, 'd') # base 10
'255'
>>> format(255, 'o') # base 8
'377'
>>> format(255, 'x') # base 16
'ff'
Ответ 3
Если вы используете Numpy, существует numpy.base_repr
.
Вы можете прочитать код в numpy/core/numeric.py
. Коротко и элегантно
Ответ 4
Вышеупомянутые ответы действительно приятные. Это помогло мне много прототипа альгортима, который мне пришлось реализовать в C
Я хотел бы придумать небольшое изменение (я использовал) для преобразования десятичного числа в базу символьного пространства
Я также игнорировал отрицательные значения только для краткости и тот факт, что математические неверные
- > другие правила модульной арифметики
- > другая математика, если вы используете двоичный, oct или hex → diff в неподписанных и подписанных значениях
def str_base(number, base):
(d,m) = divmod(number,len(base))
if d > 0:
return str_base(d,base)+base[m]
return base[m]
которые приводят к следующему выводу
>>> str_base(13,'01')
'1101'
>>> str_base(255,'01')
'11111111'
>>> str_base(255,'01234567')
'377'
>>> str_base(255,'0123456789')
'255'
>>> str_base(255,'0123456789abcdef')
'ff'
>>> str_base(1399871903,'_helowrd')
'hello_world'
если вы хотите использовать padd с символом нулевого знака, вы можете использовать
symbol_space = 'abcdest'
>>> str_base(734,symbol_space).rjust(0,symbol_space[0])
'catt'
>>> str_base(734,symbol_space).rjust(6,symbol_space[0])
'aacatt'
Ответ 5
просмотрите это.
def int2str(num, base=16, sbl=None):
if not sbl:
sbl = '0123456789abcdefghijklmnopqrstuvwxyz'
if len(sbl) < 2:
raise ValueError, 'size of symbols should be >= 2'
if base < 2 or base > len(sbl):
raise ValueError, 'base must be in range 2-%d' % (len(sbl))
neg = False
if num < 0:
neg = True
num = -num
num, rem = divmod(num, base)
ret = ''
while num:
ret = sbl[rem] + ret
num, rem = divmod(num, base)
ret = ('-' if neg else '') + sbl[rem] + ret
return ret
Ответ 6
digit_to_char
может быть реализовано следующим образом:
def digit_to_char(digit):
return (string.digits + string.lowercase)[digit]
Ответ 7
Я когда-то написал свою собственную функцию с той же целью, но теперь смущающе сложно.
from math import log, ceil, floor
from collections import deque
from itertools import repeat
from string import uppercase, digits
import re
__alphanumerals = (digits + uppercase)
class InvalidBaseError(ValueError): pass
class FloatConvertError(ValueError): pass
class IncorrectBaseError(ValueError): pass
def getbase(number, base=2, frombase = 10):
if not frombase == 10:
number = getvalue(number, frombase)
#getvalue is also a personal function to replicate int(number, base)
if 1 >= base or base >= len(__alphanumerals) or not floor(base) == base:
raise InvalidBaseError("Invalid value: {} entered as base to convert
to. \n{}".format(base,
"Assert that the base to convert to is a decimal integer."))
if isinstance(number, str):
try:
number = atof(number)
except ValueError:
#The first check of whether the base is 10 would have already corrected the number
raise IncorrectBaseError("Incorrect base passed as base of number -> number: {} base: {}".format(number, frombase))
#^ v was supporting float numbers incase number was the return of another operation
if number > floor(number):
raise FloatConvertError("The number to be converted must not be a float. {}".format(number))
isNegative = False
if number < 0:
isNegative = True
number = abs(number)
logarithm = log(number, base) if number else 0 #get around number being zero easily
ceiling = int(logarithm) + 1
structure = deque(repeat(0, ceiling), maxlen = ceiling)
while number:
if number >= (base ** int(logarithm)):
acceptable_digit = int(number / (base ** floor(logarithm)))
structure.append(acceptable_digit if acceptable_digit < 10 else __alphanumerals[acceptable_digit])
number -= acceptable_digit * (base ** floor(logarithm))
else:
structure.append(0)
logarithm -= 1
while structure[0] == 0:
#the result needs trailing zeros
structure.rotate(-1)
return ("-" if isNegative and number else "") + reduce(lambda a, b: a + b, map(lambda a: str(a), structure))
Я думаю, что функция strbase должна поддерживать только base >= 2 и <= 36, чтобы предотвратить конфликт с другими инструментами в python, например int.
Кроме того, я думаю, что только один случай алфавитов должен использоваться предпочтительно в верхнем регистре, чтобы предотвратить конфликт с другими функциями, такими как int, поскольку он будет рассматривать как "a", так и "A" как 10.
from string import uppercase
dig_to_chr = lambda num: str(num) if num < 10 else uppercase[num - 10]
def strbase(number, base):
if not 2 <= base <= 36:
raise ValueError("Base to convert to must be >= 2 and <= 36")
if number < 0:
return "-" + strbase(-number, base)
d, m = divmod(number, base)
if d:
return strbase(d, base) + dig_to_chr(m)
return dig_to_chr(m)
Ответ 8
Вы также можете попробовать подход ниже
def base10toN(num,n):
return ((num == 0) and "0" ) or ( base10toN(num // n, n).strip("0") + "0123456789abcdefghijklmnopqrstuvwxyz"[:n][num % n])
Ответ 9
Немного googling приносит this. Один из комментариев рассказывает о встроенных функциях Python:
int(x [,base]) converts x to an integer
long(x [,base]) converts x to a long integer
float(x) converts x to a floating-point number
complex(real [,imag]) creates a complex number
chr(x) converts an integer to a character
unichr(x) converts an integer to a Unicode character
ord(c) converts a character to its integer value
hex(x) converts an integer to a hexadecimal string
oct(x) converts an integer to an octal string
Но ни один из них не кажется правильным. Думаю, вам просто нужно закодировать свою собственную функцию. В ссылке есть пример кода.
Ответ 10
Вот мое решение:
def int2base(a, base, numerals="0123456789abcdefghijklmnopqrstuvwxyz"):
baseit = lambda a=a, b=base: (not a) and numerals[0] or baseit(a-a%b,b*base)+numerals[a%b%(base-1) or (a%b) and (base-1)]
return baseit()
объяснение
В любой базе каждое число равно a1+a2*base**2+a3*base**3...
"Миссия" - найти все.
Для каждого N=1,2,3...
код изолирует aN*base**N
путем "mouduling" с помощью b для b=base**(N+1)
который срезает все больше, чем N, и нарезая все a, что их серийный номер меньше N, уменьшая a каждый раз, когда функция вызывается текущим aN*base**N
Base%(base-1)==1
поэтому base**p%(base-1)==1
и, следовательно, q*base^p%(base-1)==q
только с одним исключением, когда q=base-1
который возвращает 0
. Чтобы исправить это, в случае, если он возвращает 0
, функция проверяет, равен ли он 0
с начала.
преимущества
В этом примере есть только одно умножение (вместо деления) и несколько экземпляров модуля, которые занимают относительно небольшое количество времени.
Ответ 11
Похоже, это моё время сиять. Хотите верьте, хотите нет, ниже приведен портированный и модифицированный код Scratch, который я написал почти три года назад, чтобы увидеть, насколько быстро я могу преобразовать из денари в шестнадцатеричное.
Проще говоря, он работает, сначала беря целое число, основание и необязательную сопровождающую строку цифр, а затем вычисляя каждую цифру преобразованного целого числа, начиная с наименее значимого.
def int2base(num, base, abc="0123456789abcdefghijklmnopqrstuvwxyz"):
if num < 0:
return '-' + int2base(-num, base, abc)
else:
output = abc[num % base] # rightmost digit
while num >= base:
num //= base # move to next digit to the left
output = abc[num % base] + output # this digit
return output
На моем собственном ПК этот код смог выполнить 10 миллионов итераций, используя диапазон ввода 0-9999 и базовый 36, последовательно менее 5 секунд. Используя тот же тест, я обнаружил, что это по крайней мере на 4 секунды быстрее, чем любой другой ответ до сих пор.
>>> timeit.timeit(lambda: [int2base(n, 36) for n in range(10000)], number=1000)
4.883068453882515