【问题标题】:Reduce execution time of combinations-producing script减少组合生成脚本的执行时间
【发布时间】:2020-09-18 16:37:58
【问题描述】:

我需要减少执行生成一些组合列表的 python 脚本的时间。问题简单说明:

有两个列表:

char_list = ['a','b','c','d','e','f','g','h']
n_list = [3,2,1,2]

目标是根据n_list 中的模式创建一个包含char_list 中所有可能的字符组合的集合(列表、元组或任何你想要的),长度和顺序根据模式。 1680 个可能的例子:

(('a', 'd', 'e'), ('h', 'c'), ('b',), ('d', 'f'))

集合中的所有组合都必须像上面的这个,唯一会改变的是特定字符的位置。这就是困难开始的地方,因为有些规则不能省略:

  • 每个组合中不能有重复的字符(每个 字符只能组合出现一次)
  • 在相同的元组中更改了字符顺序的组合 以前的位置也被视为重复项(此规则 更复杂,所以让我举个例子):

假设我们的收藏中有数千种组合,突然间我们注意到四个看起来几乎相同:

(('a', 'c', 'e'), ('b', 'd'), ('g',), ('f', 'h'))
(('a', 'c', 'e'), ('h', 'f'), ('g',), ('d', 'b'))
(('a', 'c', 'e'), ('f', 'h'), ('g',), ('b', 'd'))
(('a', 'e', 'c'), ('h', 'f'), ('g',), ('d', 'b'))

其中只有两个是正确的(可以属于我们的集合,顺便说一句,这种情况意味着整个集合都是错误的,因为这四个组合中有两个是错误的)哪一个?第一个很好(至少对于这个例子来说),但是在接下来的三个的情况下,只有一个很好,这是第一个(这三个中的第一个,如果我们从所有 4 个的开头算起,第二个组合),因为它出现在整个集合中的下两个之前。为什么第三和第四组合不是唯一的?因为其中具有特定字符顺序的元组的位置没有改变;只有字符交换了位置,但只有特定的元组,这并不是使整个组合独一无二的原因。再次查看第一个和第三个组合的元组。他们是一样的。但是这些元组的顺序是不同的。第一个的一个(顺序)相对于其他是唯一的。 我解决这个编码问题的方法:

import itertools as iter

char_list = ['a','b','c','d','e','f','g','h']
n_list = [3,2,1,2]

###this line creates a list of all possible combinations of characters within tuples###
char_comb_in_tuples = list(iter.chain(*[list(iter.combinations(char_list,n)) for n in n_list]))
### this is list in which the appropriate combinations will be appended###
list_of_good_combinations = []
###for loop for looping over all possible combinations of tuples from 'char_comb_in_tuples'###
for combination in iter.combinations(char_comb_in_tuples,4):
###filtering only these combinations with appropriate pattern from n_list (3,2,1,2)###
    if len([tuple for n_list_number, tuple in zip(n_list, combination) if n_list_number ==len(tuple)])==4:
###filtering only these combinations with no character duplicates###
        if len(list(iter.chain(*combination))) != len(set(list(iter.chain(*combination)))):
            pass
        else:
###appending right combination to final list###
            list_of_good_combinations.append(combination)
    else:
        pass

【问题讨论】:

    标签: python python-3.x combinations


    【解决方案1】:

    您可以使用递归函数,从itertools.combinations 的第一个给定分区中指定的列表中选取项目数,从项目池中减去选取的项目,然后将它们传递给下一个递归调用的分区,并将返回的组合与当前为第一个分区选择的每个组合合并。为了有效地从池中减去项目,您可以先将给定列表转换为集合:

    from itertools import combinations
    
    def partitioned_combinations(s, partitions):
        if partitions:
            for combination in combinations(s, r=partitions[0]):
                for combinations in partitioned_combinations(s.difference(combination), partitions[1:]):
                    yield (combination, *combinations)
        else:
            yield ()
    

    这样:

    list(partitioned_combinations(set(char_list), n_list))
    

    将返回列表中的 1680 个元组:

    [(('a', 'e', 'f'), ('c', 'd'), ('g',), ('h', 'b')),
     (('a', 'e', 'f'), ('c', 'd'), ('b',), ('h', 'g')),
     (('a', 'e', 'f'), ('c', 'd'), ('h',), ('g', 'b')),
     (('a', 'e', 'f'), ('c', 'g'), ('d',), ('b', 'h')),
     (('a', 'e', 'f'), ('c', 'g'), ('b',), ('d', 'h')),
     (('a', 'e', 'f'), ('c', 'g'), ('h',), ('d', 'b')),
     (('a', 'e', 'f'), ('c', 'b'), ('d',), ('g', 'h')),
     (('a', 'e', 'f'), ('c', 'b'), ('g',), ('d', 'h')),
     (('a', 'e', 'f'), ('c', 'b'), ('h',), ('d', 'g')),
     (('a', 'e', 'f'), ('c', 'h'), ('d',), ('g', 'b')),
     ...
    

    请注意,Python 中的集合是无序的,因此这种方法的结果不会有明确的顺序。但是,如果您确实希望它们按顺序排列,则可以安装 ordered-set 模块,以便:

    from ordered_set import OrderedSet
    list(partitioned_combinations(OrderedSet(char_list), n_list))
    

    返回:

    [(('a', 'b', 'c'), ('d', 'e'), ('f',), ('g', 'h')),
     (('a', 'b', 'c'), ('d', 'e'), ('g',), ('f', 'h')),
     (('a', 'b', 'c'), ('d', 'e'), ('h',), ('f', 'g')),
     (('a', 'b', 'c'), ('d', 'f'), ('e',), ('g', 'h')),
     (('a', 'b', 'c'), ('d', 'f'), ('g',), ('e', 'h')),
     (('a', 'b', 'c'), ('d', 'f'), ('h',), ('e', 'g')),
     (('a', 'b', 'c'), ('d', 'g'), ('e',), ('f', 'h')),
     (('a', 'b', 'c'), ('d', 'g'), ('f',), ('e', 'h')),
     (('a', 'b', 'c'), ('d', 'g'), ('h',), ('e', 'f')),
     (('a', 'b', 'c'), ('d', 'h'), ('e',), ('f', 'g')),
    ...
    

    【讨论】:

      猜你喜欢
      • 2021-12-02
      • 2017-07-10
      • 1970-01-01
      • 1970-01-01
      • 2021-08-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-15
      相关资源
      最近更新 更多