2009-09-06 12 views
5

Soy nuevo en Python. Esto es lo que estoy tratando de hacer:Convertir cadenas binarias en listas de enteros usando Python

  1. Corta una cadena binaria larga en trozos de 3 dígitos.
  2. Almacena cada "porción" en una lista llamada fila.
  3. Convierte cada porción binaria en un número (0-7).
  4. Almacene la lista convertida de números en una nueva lista llamada números.

Esto es lo que tengo hasta ahora:

def traverse(R): 
     x = 0 
     while x < (len(R) - 3): 
      row = R[x] + R[x+1] + R[x+2] 
      ??? 

Gracias por su ayuda! Es muy apreciado.

+1

y ** ¿cómo estás tratando de hacer esto? o deberíamos simplemente darte el c0dez? – SilentGhost

+0

Publicaré lo que tengo hasta ahora, aunque probablemente sea la forma incorrecta de hacerlo. – AME

Respuesta

11

Algo así debe hacerlo:

s = "110101001" 
numbers = [int(s[i:i+3], 2) for i in range(0, len(s), 3)] 
print numbers 

la salida es:

[6, 5, 1] 

Romper esto abajo paso a paso, primero:

>>> range(0, len(s), 3) 
[0, 3, 6] 

La función range() produce una lista de enteros de 0, menor que el máximo de len(s), por paso 3.

>>> [s[i:i+3] for i in range(0, len(s), 3)] 
["110", "101", "001"] 

Esta es una list comprehension que evalúa s[i:i+3] para cada i en el intervalo anterior. El s[i:i+3] es un slice que selecciona una subcadena. Finalmente:

>>> [int(s[i:i+3], 2) for i in range(0, len(s), 3)] 
[6, 5, 1] 

La función int(..., 2) convierte de binario (base 2, segundo argumento) en enteros.

Tenga en cuenta que el código anterior puede no manejar adecuadamente las condiciones de error como una cadena de entrada que no tiene un múltiplo de 3 caracteres de longitud.

+0

Gran respuesta. El desglose es particularmente útil si no entiende la sintaxis de las listas de comprensión. –

+0

Gracias! Tu respuesta se explica muy claramente.Sin embargo, tengo una pregunta, ¿qué pasa si la cadena de referencia no es un múltiplo de tres? ¿Hay alguna manera de manejar eso? – AME

+0

Bueno, debería ser un ejemplo de potencia y sintaxis de Python :) – IProblemFactory

7

Supongo que con "cadena binaria" en realidad quiere decir una cadena normal (es decir, texto) cuyos elementos son todos '0' o '1'.

Así que para los puntos 1 y 2,

row = [thestring[i:i+3] for i in xrange(0, len(thestring), 3)] 

, por supuesto, el último elemento será solamente 1 o 2 caracteres de longitud si len(thestring) no es un múltiplo exacto de 3, eso es inevitable ;-).

Para los puntos 3 y 4, me gustaría sugerir la construcción de un diccionario de temperatura auxiliar y almacenarlo:

aux = {} 
for x in range(8): 
    s = format(x, 'b') 
    aux[s] = x 
    aux[('00'+s)[-3:]] = x 

de manera que los puntos 3 y 4 sólo se convertirá en:

numbers = [aux[x] for x in row] 

Esta búsqueda debe dict será mucho más rápido que convertir cada entrada sobre la marcha.

Editar: se ha sugerido que explicar por qué estoy haciendo dos entradas en aux para cada valor de x. El punto es que s puede tener cualquier longitud de 1 a 3 caracteres, y para las cortas quiero dos entradas, una con s como tal (porque como mencioné, el último elemento en row bien puede ser más corto que 3 ...), y uno con el izquierdo acolchado a una longitud de 3 con 0 s.

El sub-expresión ('00'+s)[-3:] computa "s izquierda-acolchado con 'de 0 a una longitud de 3" mediante la adopción de los 3 últimos caracteres (que es la parte [-3:] slicing) de la cadena obtenida mediante la colocación de ceros a la izquierda de s (esa es la parte '00'+s). Si s ya tiene 3 caracteres, toda la subexpresión será igual a s, por lo que la asignación a esa entrada de aux es inútil pero inofensiva, por lo que me resulta más sencillo ni siquiera molestarme en verificar (anteponer un if len(s)<3: también estaría bien, cuestión de gustos; -).

Hay otros enfoques (por ejemplo, formatear x de nuevo si es necesario) pero este no es el meollo del código (se ejecuta solo 8 veces para construir la "tabla de búsqueda" auxiliar, después de todo ;-), entonces no lo hice le presto suficiente atención.

... ni hice una prueba de unidad, por lo que tiene un error en una caja de esquina oscura. Puedes verlo...?

Supongamos que tiene row'01' como la última entrada: esa llave, después de que mi código está construida ha aux, no estará presente en aux (tanto 1 y 001 será, pero eso es consuelo escasa ;-). En el código anterior utilizo el original s, '1', y la versión acolchada de longitud tres, '001', pero la versión intermedia de longitud dos, ¡oops!, Se pasó por alto ;-).

lo tanto, aquí es una forma correcta de hacerlo ...:

aux = {} 
for x in range(8): 
    s = format(x, 'b') 
    aux[s] = x 
    while len(s) < 3: 
    s = '0' + s 
    aux[s] = x 

... sin duda más simple y más obvia, pero, más importante aún, CORRECTO ;-).

+0

Es una especie de truco malicioso con la indexación de cadenas. Es posible que desee explicar lo que está haciendo para que el OP no tenga la tentación de copiarlo/pegarlo en su código sin entenderlo. –

+0

@Chris, buena idea, edición para explicar. –

+1

Mira, arriba en el cielo! Códigos, explica, ¡incluso convierte los errores en lecciones! ¡Es SUPER MARTELLI, aquí para chupar mi cuota diaria de votos favorables! –

0

¡Grandes respuestas de Greg y Alex! ¡Las comprensiones de listas y el corte son tan pitónicas! Para cadenas de entrada cortas, no me molestaría con el truco de búsqueda del diccionario, pero si la cadena de entrada fuera más larga, usaría gen-exps en lugar de list-comps, es decir:

row = list (lacadena [i: i + 3] para i en xrange (0, len (lacadena), 3))

y

números = lista (aux [x] para x en fila)

desde gen-exp funciona mejor

+0

En realidad, las composiciones de la lista funcionan igual o más rápido que la generación. exprs (en ejemplos que he probado). No hagas una optimización prematura en ningún caso. – jfs

+0

@JF, sí - Ojalá hubiera UNA sola forma obvia de hacerlo, pero, dado que, por desgracia, hay dos, los listcomps son de hecho más rápidos que 'list (genexp)' (potencialmente por un factor significativo) y generalmente se debe preferir cuando ambas formas son posibles y "obvias". –

+0

Dang! Estoy corregido. Gracias, JF y Alex. Mi concepto erróneo del rendimiento de genexp estaba enraizado en un modismo relacionado de Python: el de usar cualquier iterativo [acotado] para crear una lista: newlist = list (x) es mucho más rápido (y más legible) que newlist = [y para y en x] y dado que genexps esencialmente devuelve un iterador, asumí erróneamente que la lista (some_genexp) sería más rápida que la lista correspondientecomp ... Lección aprendida: Utilizaré timeit de forma más sistemática. ¡Por cierto, todo es culpa de Alex! Obtuve el modismo de lista (x) de Python cookBook. mjv

0

¿No sería más fácil:

(quería una matriz de los 3 bits superiores de una variable que contenían el número entero 29)

formato sus variables y matrices primera

a = ''

b = []

robé esto desde un muy buen ejemplo en este foro, que formatea el número entero 29 en 5 bits, los bits cero throug h cuatro y pone la cadena de bits en la variable de cadena "a". [Editado] necesario para cambiar el formato de 0: 5b a 0: 05b, con el fin de ceros cojín cuando el número entero es < 7.

a = '{0: 05b}'. Formato (29)

vistazo a su variable de cadena

un

'11101'

dividir su cadena en una matriz

b [0: 3] = a [0: 3]

esto es exactamente lo que quería.

b

[ '1', '1', '1']

1

Si usted está tratando con el tratamiento de datos de cualquier tipo, me gustaría recomendar el excelente módulo bitstring:

>>> import bitstring 
>>> bits = bitstring.Bits('0b110101001') 
>>> [b.uint for b in bits.cut(3)] 
[6, 5, 1] 

Descripción de la home page:

un módulo de Python que hace que la creatio n, manipulación y análisis de datos binarios tan simple y natural como sea posible.

Bitstrings se pueden construir a partir de enteros, flotantes, hexadecimales, octal, binarios, bytes o archivos. También se pueden crear e interpretar utilizando cadenas de formato flexible .

Bitstrings se pueden cortar, unir, invertir, insertar en, sobrescribir, etc. con métodos simples o mediante la notación de división. Ellos también se pueden leer, buscar y reemplazar, y navegaron en, similar a un archivo o secuencia.

Internamente, los datos de bits se almacenan de manera eficiente en matrices de bytes, el módulo se ha optimizado para la velocidad y la excelente cobertura de códigos es dada por más de 400 pruebas unitarias.

Cuestiones relacionadas