Newbie looking for elegant solution

Steven D'Aprano steve+comp.lang.python at pearwood.info
Wed Mar 25 01:24:59 EDT 2015


On Wednesday 25 March 2015 14:13, otaksoftspamtrap at gmail.com wrote:

> I have a list containing 9600 integer elements - each integer is either 0
> or 1.
> 
> Starting at the front of the list, I need to combine 8 list elements into
> 1 by treating them as if they were bits of one byte with 1 and 0 denoting
> bit on/off (the 8th element would be the rightmost bit of the first byte).
> 
> The end result should be a new list that is 8 x shorter than the original
> list containing integers between 0 and 255.
> 
> Speed is not of utmost importance - an elegant solution is. Any
> suggestions?

Collate the list into groups of 8. Here, I pad the list with zeroes at the 
end. If you prefer to drop any excess bits instead of padding them, use 
itertools.izip instead of izip_longest.


import itertools
mylist = [1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1]
grouped = itertools.izip_longest(*([iter(mylist)]*8), fillvalue=0)



Now convert each group of eight into a byte:

def byte(bits):
    n = 0
    for b in bits:
        assert b in (0, 1)
        n = n*2 + b
    return n

[byte(x) for x in grouped]


Or if you prefer using built-ins:

[int(''.join(str(b) for b in x), 2) for x in grouped]

I have no idea which will be faster.


Exercise for the reader: izip will drop any bits that don't make up an 
octet. izip_longest will pad with zeroes on the least-significant side, e.g. 
[1, 1] -> 192. How to pad on the most-significant side, or equivalently, 
don't pad at all, so that [1, 1] -> 3?



-- 
Steve




More information about the Python-list mailing list