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