Monday, March 30, 2020

Itertools Compress and Bitmask Conversions

Itertools Compress and Bitmask Conversions

Itertools Compress and Converting Bitmasks to Lists (and vice versa)

In [1]:
import itertools
Itertools Compress

Make an iterator that filters elements from data returning only those that have a corresponding element in selectors that evaluates to True.

Stops when either the data or selectors iterables has been exhausted.

In [2]:
data = 'ABCDEFG'
masklist = [1,0,0,1]
result = [x for x in itertools.compress(data,masklist)]
print(result)
['A', 'D']

If the mask has shorter length than data, then you may want the mask to be right-justified.

Especially if the mask was produced by converting an integer to a list ( 9 -> [1,0,0,1] )

In other words, you wanted the mask to look like this [0,0,0,0,1,0,0,1]

In [3]:
# perform compress after padding the mask with leading zeros
def padCompress(data,mask):
    if len(mask)<len(data):
        pad = [0]*(len(data)-len(mask))
        mask = pad + mask
    return(itertools.compress(data,mask))
        
data = 'ABCDEFG'
masklist = [1,0,0,1]
result = [x for x in padCompress(data,masklist)]
print(result)
['D', 'G']
In [4]:
# converting binary list to integer  
# using bit shift + | operator 
def list2int(binlist):
    retval = 0
    for bit in binlist:
        retval = (retval<<1)|bit
    return retval

masklist = [1,0,0,1]
x = list2int(masklist)
print(x)
9
In [5]:
# converting integer to binary list, we can use bin() function
s = bin(9)
print(s)
0b1001
In [6]:
# get rid of the leading '0b' piece
s = bin(9)[2:]
print(s)
1001
In [7]:
# and if you want to pad the left to a certain length
s = bin(9)[2:].zfill(8)
print(s)
00001001
In [8]:
# int2list function with optional length argument, returns a list
def int2list(num,length=0):
    if length > 0:
        retval = [int(i) for i in bin(num)[2:].zfill(length)]
    else:
        retval = [int(i) for i in bin(num)[2:]]
    return retval

x = 9
list1 = int2list(x)
print(list1)

list2 = int2list(x,8)
print(list2)
[1, 0, 0, 1]
[0, 0, 0, 0, 1, 0, 0, 1]
In [9]:
# two more functions that might be useful: AND and OR using bitmask lists
# note that these functions use the list2int and int2list functions from above

def listOR(list1,list2):
    n1 = list2int(list1)
    n2 = list2int(list2)
    n3 = n1|n2
    list3 = int2list(n3)
    return list3

def listAND(list1,list2):
    n1 = list2int(list1)
    n2 = list2int(list2)
    n3 = n1&n2
    list3 = int2list(n3)
    return list3

list1 = [0,1,1,1,1,0,0,0]
list2 = [0,0,0,0,1,1,1,0]

print("OR: ",listOR(list1,list2))
print("AND:",listAND(list1,list2))
OR:  [1, 1, 1, 1, 1, 1, 0]
AND: [1, 0, 0, 0]
In [10]:
# versions of listOR and listAND which pad the returned list 
# to the length of the longer input list 

def listOR(list1,list2):
    n1 = list2int(list1)
    n2 = list2int(list2)
    n3 = n1|n2
    list3 = int2list(n3,max(len(list1),len(list2)))
    return list3

def listAND(list1,list2):
    n1 = list2int(list1)
    n2 = list2int(list2)
    n3 = n1&n2
    list3 = int2list(n3,max(len(list1),len(list2)))
    return list3

list1 = [0,1,1,1,1,0,0,0]
list2 = [0,0,0,0,1,1,1,0]

print("OR: ",listOR(list1,list2))
print("AND:",listAND(list1,list2))
OR:  [0, 1, 1, 1, 1, 1, 1, 0]
AND: [0, 0, 0, 0, 1, 0, 0, 0]