【问题标题】:Grouping the combination results into a list with sub-lists将组合结果分组到带有子列表的列表中
【发布时间】:2018-01-05 19:44:27
【问题描述】:

我有列表a:

a = [0,1,2,3,4,5]

然后我创建此列表的所有三元素组合。由于与二进制 3 位字符串形式的等效项匹配,因此结果被分组在 sublistach 中。比如结果[0,4,5]对应序列001,因为每个偶数对应0,奇数对应1。

我在 cmets 中使用的代码:

import itertools as it
import itertools

# I create three-element combinations of zeros and ones
combinations_3bit = list(map(list, itertools.product([0,1], repeat=3)))
# output: [[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]]

# I create a list of strings with values from the list `3bit_combinations`
a=[]
for i in range(len(combinations_3bit)):
    a2 =''.join(map(str, [1 if x%2 else 0 for x in combinations_3bit[i]]))
    a.append(a2)
# output: ['000', '001', '010', '011', '100', '101', '110', '111'] 

# I remove repetitions in pairs of type 001 with 100, 011 with 110, etc.
combinations_3bit_without_repetition = [v for k, v in enumerate(a) if v[::-1] not in a[:k]] 
# output: ['000', '001', '010', '011', '101', '111'] 

b = [0,1,2,3,4,5]

good = []
for i in range(len(combinations_3bit_without_repetition)):
    c=[]
    for u in it.combinations(b, 3):       
        u1 = list(u)                  
        y =''.join(map(str, [1 if x%2 else 0 for x in u1]))
        if y == combinations_3bit_without_repetition[i]:
           c.append(u1)
    good.append(c) 

# output: [[[0, 2, 4]], [[0, 2, 3], [0, 2, 5], [0, 4, 5], [2, 4, 5]], [[0, 1, 2], [0, 1, 4], [0, 3, 4], [2, 3, 4]], [[0, 1, 3], [0, 1, 5], [0, 3, 5], [2, 3, 5]], [[1, 2, 3], [1, 2, 5], [1, 4, 5], [3, 4, 5]], [[1, 3, 5]]]

能否更好、更经济地解决这个问题? 因为上面的解决方案似乎是“围绕”的,例如函数it.combinations 在列表combinations_3bit_without_repetition 中的每个索引i 之后返回所有可能的组合,只有这样,条件才会筛选匹配的组合。在大列表的情况下,这个解决方案很弱;)

【问题讨论】:

    标签: python python-3.x list combinations itertools


    【解决方案1】:

    有一种更好的方法可以生成您需要的二进制字符串:

    import itertools
    
    strings = ['{0:03b}'.format(i) for i in range(8)]
    b = [0,1,2,3,4,5]
    combinations = [list(x) for x in itertools.combinations(b, 3)]
    
    dct = {}
    
    for x in combinations:
      y = ''.join(str(j%2) for j in x)
      if y in dct:
        dct[y].append(x)
      else:
        dct[y] = [x]
    
    print(dct)
    

    输出:

    {'010': [[0, 1, 2], [0, 1, 4], [0, 3, 4], [2, 3, 4]], '011': [[0, 1, 3], [0, 1, 5], [0, 3, 5], [2, 3, 5]], '001': [[0, 2, 3], [0, 2, 5], [0, 4, 5], [2, 4, 5]], '000': [[0, 2, 4]], '101': [[1, 2, 3], [1, 2, 5], [1, 4, 5], [3, 4, 5]], '100': [[1, 2, 4]], '110': [[1, 3, 4]], '111': [[1, 3, 5]]}
    

    检查这是否满足您的需求。它创建一个字典,其中每个键是一个长度为 3 的二进制字符串,每个值是一个与二进制字符串匹配的组合数组。

    【讨论】:

    • 感谢您的回答,但是对于二进制字符串,存在一个较小的问题。我更关心优化good 列表的创建。
    • 你能澄清更多你想要什么作为你的输出吗?您希望列表的所有长度为 3 的排列都与特定模式匹配?
    • 就这样。即,例如,查找 000、i001 模式的所有组合,依此类推。当然,没有[0,2,5]和[5,2,0]类型的一些重复。但这也是较小的问题之一;)
    • 所以[0,1,2] 的组合对应于'010',因此您希望[0,1,2]good 中?
    • 这正是它的全部意义所在。
    【解决方案2】:

    这是使用您的b 和您的combinations_3bit_without_repetitionitertools.groupby 解决方案:

    def binarize(x):
        return ''.join(map(str, map((1).__and__, x)))
    
    srted = sorted(itertools.combinations(b, 3), key=binarize)
    allowed = set(combinations_3bit_without_repetition)
    result = [list(grp) for bn, grp in itertools.groupby(srted, binarize) if bn in allowed]
    
    print(result)
    

    打印:

    [[(0, 2, 4)], [(0, 2, 3), (0, 2, 5), (0, 4, 5), (2, 4, 5)], [(0, 1, 2), (0, 1, 4), (0, 3, 4), (2, 3, 4)], [(0, 1, 3), (0, 1, 5), (0, 3, 5), (2, 3, 5)], [(1, 2, 3), (1, 2, 5), (1, 4, 5), (3, 4, 5)], [(1, 3, 5)]]
    

    【讨论】:

    • 我喜欢这个解决方案。很干净
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-03-06
    • 1970-01-01
    • 2013-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多