简体   繁体   中英

Permutation of two “linked” lists in python

Wondering if there is a way to use itertools.permutations() (or something else or similar) on two lists and in a way link the output of both so there is a one-to-one mapping between their outputs.

Example: I have a byte x = 0xE3, x_bit = BitArray(x).bin = 11100011 that is the result of a specific order of eight signals (bit streams) (d0-d7) , say [d0,d3,d4,d7,d2,d1,d6,d5] . If I want to re-arrange the order of the signals to eg get 0xEC = 11101100 I have several possibilities due to non-uniqueness of the binary domain, but two possibilities would be [d0,d3,d4,d7,d6,d6,d1,d2] and [d3,d0,d4,d7,d6,d6,d1,d2]

Question is thus, is there a simple way to link the outputs that result in 0xEC to the order of the data signals (d0-d7) that results in the desired bit sequence, eg in one way "hook" the original signal order to the different bits so that I end up with a list of the possible combinations but without losing the non-uniqueness that the binary permutations provide? I was first thinking of appending the signal name to the bit value as a string, but then of course it will be unique entries in the list and not all valid permutations will be among the result.

This is something that I in the end will be using on a byte array of 5-6 bytes so eventually I will have to save all the combinations that result in the desired output on all byte positions in the array, but in due time, first things first.

import itertools
import bitstring

input_byte = 0xE3 
input_bitseq = bitstring.BitArray(inpu_byte) # 1110 0011
signal_order = ['d0','d3','d4','d7','d2','d1','d6','d5'] # input signal order

perms = list(itertools.permutations(intput_bitseq))
for x in perms:
    print(x)

Sample output:

('1', '1', '1', '0', '0', '0', '1', '0')
('1', '1', '0', '1', '0', '0', '1', '1')
('1', '1', '1', '0', '0', '1', '1', '0')
('1', '1', '0', '0', '1', '1', '0', '1')
('1', '1', '0', '0', '1', '1', '1', '0')
('1', '1', '0', '0', '1', '1', '0', '1')
('1', '1', '0', '0', '1', '0', '1', '1')
('1', '1', '0', '0', '1', '0', '1', '1')
('1', '1', '0', '0', '1', '1', '1', '0')

(list will have 40k something entries). Now, only a subset of these entries actually equals 0xEC , and these are of course easy to find, but I would like to also know which combination of the signals (d0-d7) that maps to the different bit sequences that all match 0xEC .

Extra explanation:

Original data:
MSB b7,b6,b5,b4,b3,b2,b1,b0 LSB
0x90        0xE3        0xF5        0xB0        0x9F        0xA2
1001 0000   1110 0011   1111 0101   1011 0000   1001 1111   1010 0010


Switch positions: b1<->b3, b0<->b2 
MSB b7,b6,b5,b4,b1,b0,b3,b2 LSB
0x90        0xEC        0xF5        0xB0        0x9F        0xA8
1001 0000   1110 1100   1111 0101   1011 0000   1001 1111   1010 1000


Switch positions: b1<->b0, b3<->b2
MSB b7,b6,b5,b4,b0,b1,b2,b3 LSB
0x90        0xEC        0xFA        0xB0        0x9F        0xA4
1001 0000   1110 1100   1111 1010   1011 0000   1001 1111   1010 0100


Switch positions: b5<->b1
MSB b7,b6,b1,b4,b0,b5,b2,b3 LSB
0x90        0xEC        0xDE        0x94        0xBB        0xA4
1001 0000   1110 1100   1101 1110   1001 0100   1011 1011   1010 0100


Switch positions: b0<->b6
MSB b7,b0,b1,b4,b6,b5,b2,b3 LSB

Final/desired output
0x90        0xEC        0xDE        0x94        0xF3        0xA4
1001 0000   1110 1100   1101 1110   1001 0100   1111 0011   1010 0100

I am not 100% sure if I understand what you are trying to do here. As I understand it, you want all the permutations of the positions in the source bit array that yield the target bit array.

The naive approach would be to generate all the permutations and then check which of those correspond to the target, but those would be 8! = 40k 8! = 40k permutations. That's not terribly much, but could be a problem for longer sequences or when doing this rather often. Alternatively, you could get all the permutations for the ones and zeros and distribute them to fit your result; those would be just 5!*3! = 720 5!*3! = 720 in your example (more balanced == fewer/better).

Something like this (note: I just used a string instead of a BitArray, but that should not matter here)

>>> bits = "11100011"
>>> trgt = "11101100"
>>> ones  = [i for i, e in enumerate(bits) if e == "1"]
>>> zeros = [i for i, e in enumerate(bits) if e == "0"]

>>> from itertools import permutations
>>> res = [[next(p1 if b == "1" else p2) for b in trgt] for p1, p2 in 
...        ((iter(p1), iter(p2)) for p1 in permutations(ones) 
...                              for p2 in permutations(zeros))]
...
>>> res[0]
[0, 1, 2, 3, 6, 7, 4, 5]
>>> len(res)
720
>>> set(''.join(bits[i] for i in l) for l in res)
{'11101100'}

This gives you the solution for one byte. Now if I understood that multiple-bytes-part correctly, you are looking for one transpositions of bits that can be applied to all the bytes. In this case, the number of solutions will indeed quickly get lower. You could use the above algorithm to get all the solutions for the individual bytes and then get the set.intersection of those (first convert the lists to tuples to make them hashable), or get the solutions for the first byte (or better: the most "balanced" one, having the lowest number of solutions to begin with) and then check which of those also solve the others.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM