BlueMoon93 BlueMoon93 - 21 days ago 5
Python Question

Extending integer list to 1-out-of-n binary list

Given maximum a list

l
with size
r
of integers with
N
bits, how to do I create a list
binaryL
with size
r*N
where the values reflect the positive bits of
l
?

Example, for
N=2
bits:

l = [1, 0, 3] --> [01, 00, 11] (in bits)


becomes

binaryL = [0, 0, 1, 1, 0, 1]


where each group of
r
integers equals each bit. In other words, the first
0, 0, 1
is the first bit of
l
, and the final
1, 0, 1
is the last bit of
l
.

Another option is to just obtain the bits in their order, where

binaryL = [0, 1, 0, 0, 1, 1]


In this case, each value is converted to its bits.




For those wondering about performance,

import random
from itertools import chain
import time

N=8
l=[random.randrange(1,2**N,1) for _ in range (10000000)]
r=len(l)

a = time.clock()
res1 = []
for i in l:
res1 += [int(b) for b in "{0:b}".format(i).rjust(N, '0')]

b = time.clock()
res2 = list(map(int, chain.from_iterable(bin(i)[2:].zfill(N) for i in l)))

c = time.clock()
res3 = list(map(int, ''.join(bin(i)[2:].zfill(N) for i in l)))

d = time.clock()
res4 = [0] * N * r
for ind, binary in enumerate(map(bin, l)):
for ind_bit, bit in enumerate(binary[2:].zfill(N)):
res4[r * ind_bit + ind] = int(bit)

e = time.clock()
res5 = list(map(int, chain.from_iterable(zip(*[bin(i)[2:].zfill(N) for i in l]))))

f = time.clock()

# res1, res2 and res3 are show bits by value. res4 and res5 shows bits by index
print(res1==res2)
print(res2==res3)

print(res4==res5)

print(b-a)
print(c-b)
print(d-c)
print(e-d)
print(f-e)


prints for 1000 values:

True
True
True
0.003963000000000001 # neverwalkaloner
0.0025400000000000006 # Psidom1
0.0023320000000000007 # Psidom2
0.004358000000000001 # Rockybilly
0.0021629999999999983 # Psidom3


and for 10.000.000 values

True
True
True
36.333539 # neverwalkaloner
25.674224000000002 # Psidom1
24.49611499999999 # Psidom2
47.370771000000005 # Rockybilly
66.25204 # Psidom3

Answer

Use bin to convert integer to binary representation, and pad the result to specified length with zfill(), flatten the list with chain and convert the string to int with map:

from itertools import chain

l = [1, 0, 3]
N = max(l).bit_length()           # as commented by @Jon, use this to determine the maximum 
                                  # bit length

list(map(int, chain.from_iterable(bin(i)[2:].zfill(N) for i in l)))

# [0, 1, 0, 0, 1, 1]

Without using chain, another option could be:

list(map(int, ''.join(bin(i)[2:].zfill(N) for i in l)))
# [0, 1, 0, 0, 1, 1]

A transposed version:

list(map(int, chain.from_iterable(zip(*[bin(i)[2:].zfill(N) for i in l]))))
# [0, 0, 1, 1, 0, 1]