2012-04-25 15 views
8

我已經創建了一個方法將int轉換爲位域(在列表中)並且它可以工作,但我確定有更優雅的解決方案 - 我只是盯着它爲了長久。整數位域爲列表

我很好奇,你會如何將int轉換爲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) 

回答

22

如何:

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

這給你

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

這隻適用於正整數,雖然。

編輯:

轉換爲int使用int()是矯枉過正這裏有點。這是快了很多:

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

見時機:

>>> 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爲漂亮的時序考慮 – snugglo 2012-04-25 19:23:27

+0

'[123 >> i和1在範圍內(7,-1,-1)]'是我機器上最快的。 – tMC 2012-04-25 19:32:51

+0

@tMC:我已經在Python 2.7.3和3.2.3下重做了我的兩臺PC(Win 7 Ultimate 64bit)上的計時,而且我的解決方案始終快於至少20%(Python 2)和45%( Python 3)。 – 2012-04-25 19:38:36

4

嘗試

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

這並不適用於負N功不過,當你看到給你一個字符串列表

+1

+1,我似乎忘記了總是有'list()'構造函數。 – Fenikso 2012-04-25 19:06:03

+0

即使它不返回整數列表。 – Fenikso 2012-04-25 19:09:31

+0

這不是tMC要求的。他需要一個整數列表,你給他一個字符串列表。和list()的構造函數一樣好,這裏不是正確的工具。 – 2012-04-25 19:09:56

16

這不使用bin

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

,這是如何處理的任意整數這樣:

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

bit_length

如果你想在列表的索引0對應於LSB的INT,改變區間整理,即

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

另外,在使用n.bit_length()可以,如果故障點你試圖表示固定長度的二進制值。它返回表示n的最小位數。

+0

這很完美 - 我知道我有一個列表理解丟失 – tMC 2012-04-25 19:07:10

+3

當然這隻能處理8位整數。 – 2012-04-25 19:11:16

+1

它可以用這種方式處理任何整數: [n >> i&1 for i in range(n.bit_length() - 1,-1,-1)] – mennanov 2016-02-25 08:20:32

0

我這樣做是爲我的節目裏你指定一個模板,從一個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)] 

如何在模板中使用
,指定與您比特整數尺寸:(小白友好)

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

,或者你可以指定每個值的比特位數使用字符串需要210

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

編輯:反之亦然:(分離代碼)

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

的代碼:

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:更快的代碼^