python

时间:2019-01-18 12:44:16

标签: python permutation itertools

想知道是否有一种方法可以在两个列表上使用itertools.permutations()(或其他类似方法),并以某种方式链接两个列表的输出,从而在它们的输出之间存在一对一的映射。 / p>

示例:我有一个字节x = 0xE3, x_bit = BitArray(x).bin = 11100011,它是八个信号(位流)(d0-d7)(例如[d0,d3,d4,d7,d2,d1,d6,d5])的特定顺序的结果。如果我想重新排列信号的顺序,例如得到0xEC = 11101100由于二进制域的非唯一性,我有几种可能性,但是两种可能性是[d0,d3,d4,d7,d6,d6,d1,d2][d3,d0,d4,d7,d6,d6,d1,d2]

因此,存在一种简单的方法来将产生0xEC的输出链接到数据信号(d0-d7)的顺序,该信号产生所需的比特序列,例如。以一种方式“钩住”原始信号顺序到不同的位,以便最终得到可能组合的列表,但又不丢失二进制排列提供的非唯一性?我最初想到的是将信号名称作为字符串附加到位值之后,但是当然,它将是列表中的唯一条目,并且并非所有有效的排列都将包含在结果中。

这是我最终将在5-6个字节的字节数组上使用的东西,因此最终我将必须保存所有组合,以使数组的所有字节位置上都得到所需的输出,但是由于时间,首先是事情。

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)

示例输出:

('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')

(列表将有40k条目)。现在,这些条目中只有一个子集实际上等于0xEC,这些当然很容易找到,但是我还想知道映射到不同位序列的信号(d0-d7)的哪种组合,全部匹配0xEC

额外说明:

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

1 个答案:

答案 0 :(得分:0)

我不确定100%是否了解您要在这里做什么。据我了解,您希望源位数组中产生目标位数组的所有位置排列。

幼稚的方法是生成所有排列,然后检查其中哪些与目标相对应,但将是8! = 40k排列。这不是很多,但是对于较长的序列或经常这样做时可能是个问题。或者,您可以获取1和0的所有排列,并将其分配以适合您的结果;在您的示例中,这些只是5!*3! = 720(更均衡==更少/更好)。

类似这样的事情(注意:我只是使用字符串而不是BitArray,但这在这里不重要)

>>> 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'}

这为您提供了一个字节的解决方案。现在,如果我正确理解了多字节部分,那么您正在寻找一种可以应用于 all 个字节的位转换。在这种情况下,解决方案的数量确实会迅速减少。您可以使用上述算法获取单个字节的所有解决方案,然后获取其中的set.intersection(首先将列表转换为元组以使其可哈希化),或者获取第一个字节的解决方案(或更优) :最“平衡”的解决方案,以最少的解决方案开始),然后检查其中哪些解决方案也可以解决其他问题。