2015-08-29 19 views
2

我有整數1和0,代表8位二進制字節長1維列表。什麼是整潔的方式來創建一個新的列表,包含整數字節。該循環雖然每一位精心結構:Python的比特列表以字節列表

,熟悉C,但新的Python的,我已經在我使用C做的方式編碼它。不過,我意識到Python over C的重點在於,這些事情通常可以緊湊而優雅地完成,我應該學會如何做到這一點。也許使用列表理解?

這工作,但對於更多的「Python化」的方式的建議,將不勝感激:

#!/usr/bin/env python2 
bits = [1,0,0,1,0,1,0,1,0,1,1,0,1,0,1,1,1,1,1,0,0,1,1,1] 
bytes = [] 
byt = "" 
for bit in bits: 
    byt += str(bit) 
    if len(byt) == 8: 
    bytes += [int(byt, 2)] 
    byt = "" 
print bytes 

$ bits-to-bytes.py 
[149, 107, 231] 

回答

3

您可以切片列表爲8種元素的塊和子元素映射到STR:

[int("".join(map(str, bits[i:i+8])), 2) for i in range(0, len(bits), 8)] 

你可以把它分解成兩個部分映射和連接一次:

mapped = "".join(map(str, bits)) 
[int(mapped[i:i+8], 2) for i in range(0, len(mapped), 8)] 

或者使用ITER並從石斑魚recipe在itertools借用:

it = iter(map(str, bits)) 
[int("".join(sli), 2) for sli in zip(*iter([it] * 8))] 

iter(map(str, bits))位str的內容映射,並創建一個iteratorzip(*iter([it] * 8))組的元素爲8子元件的組。
每個zip(*iter..消耗我們的迭代器8子元素,所以我們總能得到連續的羣體,這是同樣的邏輯在第一代碼我們只是避免需要切片切片。

由於斯文評論說,對於列表未除盡n你會使用數據壓縮類似於原來的代碼,就可以實現各種石斑魚食譜輸了,我掛來處理這些情況:

from itertools import zip_longest # izip_longest python2 

bits = [1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1,1,0] 
it = iter(map(str, bits)) 

print([int("".join(sli), 2) for sli in izip_longest(*iter([it] * 8),fillvalue="")]) 
[149, 107, 231, 2] # using just zip would be [149, 107, 231] 

fillvalue=""意味着我們墊空字符串奇數長度組,所以我們可以仍然稱int("".join(sli), 2),並得到正確的輸出如上面我們留下1,0服用3 * 8塊後的位置。

在自己的代碼bytes += [int(byt, 2)]可以簡單地成爲bytes.append(int(byt, 2))

+0

啊,我看到你也想過'石斑魚()'以及:)。 – Cyphase

+0

@Cyphase,是的,如果OP想要保持奇數長度的片段,那將是一條路。 –

+0

@PadraicCunningham:如果列表的長度不能被8整除,你的版本會丟棄多餘的位,因爲'zip()'在最短序列上停止。 –

1

帕德里克的解決方案是不錯的;這是另一種方式:

from itertools import izip_longest 


def grouper(iterable, n, fillvalue=None): 
    "Collect data into fixed-length chunks or blocks" 
    # Taken from itertools recipes 
    # https://docs.python.org/2/library/itertools.html#recipes 
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx 
    args = [iter(iterable)] * n 
    return izip_longest(fillvalue=fillvalue, *args) 

bits = [1, 0, 0, 1, 0, 1, 0, 1, 
     0, 1, 1, 0, 1, 0, 1, 1, 
     1, 1, 1, 0, 0, 1, 1, 1] 

byte_strings = (''.join(bit_group) for bit_group in grouper(map(str, bits), 8)) 
bytes = [int(byte_string, 2) for byte_string in byte_strings] 

print bytes # [149, 107, 231] 
+0

如果你想能夠處理一個不能被8整除的列表長度,你應該給'fillvalue'傳遞一個不同於'None'的值,否則你會得到一個像'100101NoneNone'這樣的字符串,其中'int ()'會嗆。 –