2012-04-25 10 views
8

Ho creato un metodo per convertire un int in un bitfield (in un elenco) e funziona, ma sono sicuro che ci sia una soluzione più elegante, l'ho appena visto per lungo tempo.Numero intero in bitfield come elenco

Sono curioso, come convertire un int in un bitfield rappresentato in un list?

def get(self): 
    results = [] 

    results.append(1 if (self.bits & 1) else 0) 
    results.append(1 if (self.bits & 2) else 0) 
    results.append(1 if (self.bits & 4) else 0) 
    results.append(1 if (self.bits & 8) else 0) 
    results.append(1 if (self.bits & 16) else 0) 
    results.append(1 if (self.bits & 32) else 0) 
    results.append(1 if (self.bits & 64) else 0) 
    results.append(1 if (self.bits & 128) else 0) 

    return results 

def set(self, pin, direction): 
    pin -= 1 
    if pin not in range(0, 8): raise ValueError 

    if direction: self.bits |= (2 ** pin) 
    else: self.bits &=~(2 ** pin) 

risposta

22

ne dite di questo:

def bitfield(n): 
    return [int(digit) for digit in bin(n)[2:]] # [2:] to chop off the "0b" part 

Questo vi dà

>>> bitfield(123) 
[1, 1, 1, 1, 0, 1, 1] 
>>> bitfield(255) 
[1, 1, 1, 1, 1, 1, 1, 1] 
>>> bitfield(1234567) 
[1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1] 

Questo funziona solo per i numeri interi positivi, però.

EDIT:

Conversione in int utilizzando int() è un po 'eccessivo qui. Questo è molto più veloce:

def bitfield(n): 
    return [1 if digit=='1' else 0 for digit in bin(n)[2:]] 

Vedi le temporizzazioni:

>>> import timeit 
>>> timeit.timeit("[int(digit) for digit in bin(123)[2:]]") 
7.895014818543946 
>>> timeit.timeit("[123 >> i & 1 for i in range(7,-1,-1)]") 
2.966295244250407 
>>> timeit.timeit("[1 if digit=='1' else 0 for digit in bin(123)[2:]]") 
1.7918431924733795 
+1

+1 per piacevoli considerazioni temporizzazione – snugglo

+0

'[123 >> i & 1 per i in range (7, -1, -1)] 'è il più veloce sulla mia macchina. – tMC

+0

@tMC: Ho rifatto i tempi su entrambi i miei PC (Win 7 Ultimate 64bit), in Python 2.7.3 e 3.2.3, e la mia soluzione era sempre più veloce di almeno il 20% (Python 2) e il 45% (Python 3). –

4

Prova

>>>n=1794 
>>>bitfield=list(bin(n))[2:] 
>>>bitfield 
['1', '1', '1', '0', '0', '0', '0', '0', '0', '1', '0'] 

Questo non funziona per n negativo se e come potete vedere vi dà una lista di stringhe

+1

+1, mi sembra di dimenticare che c'è un costruttore 'list()' tutto il tempo. – Fenikso

+0

Anche se non restituisce l'elenco di numeri interi. – Fenikso

+0

Questo non è quello che tMC ha chiesto. Ha bisogno di una lista di numeri interi, tu gli dai un elenco di stringhe. Per quanto piacevole possa essere il costruttore 'list()', non è lo strumento giusto qui. –

16

Questo non utilizza bin:

b = [n >> i & 1 for i in range(7,-1,-1)] 

e questo è il modo di gestire qualsiasi numero intero in questo modo:

b = [n >> i & 1 for i in range(n.bit_length() - 1,-1,-1)] 

Vedi bit_length.

Se volete indice 0 della lista per far corrispondere la LSB del int, cambiare l'ordine gamma, vale a dire

b = [n >> i & 1 for i in range(0, n.bit_length()-1)] 

Si noti anche che l'uso di n.bit_length() può essere un punto di errore, se stai cercando di rappresentare valori binari a lunghezza fissa. Restituisce il numero minimo di bit per rappresentare n.

+0

Questo è perfetto- sapevo che c'era una comprensione di lista mi mancava – tMC

+3

Naturalmente questo gestisce solo 8 bit interi. –

+1

Può gestire qualsiasi numero intero in questo modo: [n >> i & 1 per i in gamma (n.bit_length() - 1, -1, -1)] – mennanov

0

che sto facendo questo per il mio programma in cui si specifica un modello per ottenere i valori da un int:

def field(template, value): 
    sums = [int(v) if v.__class__==str else len(bin(v))-2 for v in template] 
    return [(value>> (sum(sums[:i]) if i else 0))&(~(~0<<int(t)) if t.__class__==str else t) for i,t in enumerate(template)] 

come usare
nel modello, specificare int relative alla vostra bit- dimensioni:

field([0b1,0b111,0b1111], 204) #>>> [0, 6, 12] 

oppure è possibile specificare il bit-dimensione di ogni valore necessario con le stringhe: (niubbo amichevole)

field(['1','3','4'], 204) #>>> [0, 6, 12] 

EDIT: e viceversa: (codice separato)

field(['1','3','4'], [0, 6, 12]) #>>> 204 
field([0b1,0b111,0b1111], [0,3,9]) #>>> 150 

codice:

def field(template, value): 
    res = 0 
    for t, v in zip(template, value)[::-1]: res = (res << (t.bit_length() if t.__class__ is int else int(t)))|v 
    return res 

EDIT2: codice più veloce^