tutorial lenguaje español descargar python

lenguaje - Función inversa elegante de Python de int(cadena, base)



python tutorial (9)

Aquí está mi solución:

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()

Explicación

En cualquier base, cada número es igual a a1+a2*base**2+a3*base**3... La "misión" es encontrar todos los a''s.

Para cada N=1,2,3... , el código está aislando la aN*base**N por "mouduling" por b para b=base**(N+1) que corta todas las a más que N, y cortando todos los a''s que su serie es más pequeña que N disminuyendo cada vez que la función es llamada por la aN*base**N actual aN*base**N

Base%(base-1)==1 por lo tanto base**p%(base-1)==1 y por lo tanto q*base^p%(base-1)==q con solo una excepción cuando q=base-1 que devuelve 0 . Para solucionarlo, en caso de que devuelva 0 , la función es verificar si es 0 desde el principio.

Ventajas

En esta muestra, solo hay una multiplicación (en lugar de división) y algunas instancias de módulo que toman cantidades relativamente pequeñas de tiempo.

python permite conversiones de cadena a entero usando cualquier base en el rango [2,36] usando:

int(string,base)

Estoy buscando una función inversa elegante que toma un número entero y una base y devuelve una cadena

por ejemplo

>>> str_base(224,15) ''ee''

tengo la siguiente solución:

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)

nota: digit_to_char () funciona para bases <= 169 arbitrariamente usando caracteres ascii después de ''z'' como dígitos para bases por encima de 36

¿Existe una función integrada de python, función de biblioteca o una función inversa más elegante de int (cadena, base)?


Las respuestas anteriores son realmente agradables. Me ayudó mucho prototipar un algortitmo que tuve que implementar en C

Me gustaría crear un pequeño cambio (lo usé) para convertir decimal a una base de espacio de símbolos

También ignoré los valores negativos solo por falta de precisión y el hecho de que es matemáticamente incorrecto -> otras reglas para aritmética modular -> otras matemáticas si usa binario, oct o hexadecimal -> diff en valores sin firmar y firmados

def str_base(number, base): (d,m) = divmod(number,len(base)) if d > 0: return str_base(d,base)+base[m] return base[m]

esa ventaja es la siguiente producción

>>> 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''

si quieres rellenar con el símbolo de cero adecuado puedes usar

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''


Parece que este podría ser mi momento para brillar. Lo creas o no, el siguiente es un código de Scratch portado y modificado que escribí hace casi tres años para ver qué tan rápido podía convertir de denario a hexadecimal.

En pocas palabras, funciona tomando primero un número entero y una base opcional y la cadena de numerales que lo acompaña, y luego calcula cada dígito del entero convertido comenzando con el menos significativo.

def int2base(num, base, abc="0123456789abcdefghijklmnopqrstuvwxyz"): if num < 0: return ''-'' + int2base(-num) 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

En mi propia PC, este código fue capaz de completar 10 millones de iteraciones usando el rango de entrada, 0-9999, y base, 36, en consistentemente por debajo de 5 segundos. Utilizando la misma prueba, he encontrado que es al menos 4 segundos más rápido que cualquier otra respuesta hasta el momento.

>>> timeit.timeit(lambda: [int2base(n, 36) for n in range(10000)], number=1000) 4.883068453882515



Tal vez esto no debería ser una respuesta, pero podría ser útil para algunos: la función de format integrado convierte los números a cadena en unas pocas bases:

>>> format(255, ''b'') # base 2 ''11111111'' >>> format(255, ''d'') # base 10 ''255'' >>> format(255, ''o'') # base 8 ''377'' >>> format(255, ''x'') # base 16 ''ff''


Una vez escribí mi propia función con el mismo objetivo, pero ahora es embarazosamente complicado.

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))

Aunque creo que la función strbase solo debería soportar bases> = 2 y <= 36 para evitar conflictos con otras herramientas en python, como int. Además, creo que solo se debe usar un caso de alfabetos preferiblemente en mayúsculas nuevamente para evitar conflictos con otras funciones como int, ya que considerará que tanto "a" como "A" son 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)


revisa esto.

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


Este hilo tiene algunas implementaciones de ejemplo.

De hecho, creo que su solución parece bastante agradable, incluso recursiva, que de alguna manera es agradable aquí.

Todavía lo simplificaría para eliminar el else , pero eso probablemente sea algo personal. Creo que if foo: return es muy claro, y no necesita else más para dejarlo en claro, es una rama separada.

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)

Simplifiqué el caso 0-9 en digit_to_char() , creo que str() es más claro que el constructo chr(ord()) . Para maximizar la simetría con el caso >= 10 podía factorizar un ord() , pero no me molesté, ya que añadiría una línea y la brevedad se sentiría mejor. :)


digit_to_char podría implementarse así:

def digit_to_char(digit): return (string.digits + string.lowercase)[digit]