生成同时包含括号和运算符的字符串列表的所有组合

时间:2019-03-29 20:32:29

标签: python combinations permutation itertools

假设我有一个字符串列表: l = ['A','B','C','D']

我知道要生成所有带有替换choose n的组合,我将使用itertools.combinations库方法来获取它们。

例如, list(combinations(l, 2))会给我

[['A','B'], ['A','C'],['A','D'],['B','C'],['B','D'],['C','D']]

但是,我想要括号而不是括号:

['(A,B)', '(A,C)','(A,D)','(B,C)','(B,D)','(C,D)']

现在,假设我要对此进行扩展并为这些ANDOR添加两个操作:

这样我就会得到['(A','AND','B)', '(A','OR','B)',etc.]

进一步扩展,以在n=3的情况下获得嵌套的括号:

['((A','AND','B)', 'AND', 'C)', '((A','AND','B)', 'OR', 'C)', '((A','OR','B)', 'OR', 'C)', '((A','OR','B)', 'AND', 'C)', etc.]

理想情况下,其形式为:

['((A AND B) AND C)', '((A AND B) OR C)', '((A OR B) OR C)', '((A OR B) AND C)', etc.]

因此,总而言之,我一次选择一个列表n元素的组合,并在运算符['AND','OR']上进行排列,并从左侧添加嵌套。

我已经用JavaScript做过类似的事情,但是这样做很容易,因为用户可以构建实际的句子。它不是由一组排列和组合创建的。

2 个答案:

答案 0 :(得分:2)

您可以将递归与生成器一起使用:

def op(d, n, _d, c = []):
  if _d == 1:
    yield c
  else:
    for i in d:
      if sum(isinstance(h, list) or h not in {'AND', 'OR'} for h in c) == n:
         yield from op(d, n, _d-1, c=[c, 'OR', i])
         yield from op(d, n, _d-1, c=[c, 'AND', i])
      else:
         if not c:
           yield from op(d, n, _d, c=[i])
         else:
           yield from op(d, n, _d, c=[*c, 'OR', i])
           yield from op(d, n, _d, c=[*c, 'AND', i])

result = list(op(['A','B','C','D'], 2, 2))

输出(前十个结果):

[[['A', 'OR', 'A'], 'OR', 'A'], [['A', 'OR', 'A'], 'AND', 'A'], [['A', 'OR', 'A'], 'OR', 'B'], [['A', 'OR', 'A'], 'AND', 'B'], [['A', 'OR', 'A'], 'OR', 'C'], [['A', 'OR', 'A'], 'AND', 'C'], [['A', 'OR', 'A'], 'OR', 'D'], [['A', 'OR', 'A'], 'AND', 'D'], [['A', 'AND', 'A'], 'OR', 'A'], [['A', 'AND', 'A'], 'AND', 'A']]

该解决方案将使您能够控制result中每个元素的长度和深度。例如,当生成深度为4时:

result = list(op(['A','B','C','D'], 2, 4))
print(result[:10])

输出:

[[[[['A', 'OR', 'A'], 'OR', 'A'], 'OR', 'A'], 'OR', 'A'], [[[['A', 'OR', 'A'], 'OR', 'A'], 'OR', 'A'], 'AND', 'A'], [[[['A', 'OR', 'A'], 'OR', 'A'], 'OR', 'A'], 'OR', 'B'], [[[['A', 'OR', 'A'], 'OR', 'A'], 'OR', 'A'], 'AND', 'B'], [[[['A', 'OR', 'A'], 'OR', 'A'], 'OR', 'A'], 'OR', 'C'], [[[['A', 'OR', 'A'], 'OR', 'A'], 'OR', 'A'], 'AND', 'C'], [[[['A', 'OR', 'A'], 'OR', 'A'], 'OR', 'A'], 'OR', 'D'], [[[['A', 'OR', 'A'], 'OR', 'A'], 'OR', 'A'], 'AND', 'D'], [[[['A', 'OR', 'A'], 'OR', 'A'], 'AND', 'A'], 'OR', 'A'], [[[['A', 'OR', 'A'], 'OR', 'A'], 'AND', 'A'], 'AND', 'A']]

答案 1 :(得分:2)

您可以使用itertools.combinations从给定列表中选择操作数,使用itertools.product生成操作符的组合,并再次使用itertools.product生成操作数和操作符的所有混合,然后使用一个for循环,根据选择的操作数和运算符保留嵌套列表,以构建所需的输出:

from itertools import combinations, product
def expressions(l, n):
    for (operations, *operands), operators in product(
            combinations(l, n), product(('AND', 'OR'), repeat=n - 1)):
        for operation in zip(operators, operands):
            operations = [operations, *operation]
        yield operations

使list(expressions(['A','B','C','D'], 3))返回:

[[['A', 'AND', 'B'], 'AND', 'C'],
 [['A', 'AND', 'B'], 'OR', 'C'],
 [['A', 'OR', 'B'], 'AND', 'C'],
 [['A', 'OR', 'B'], 'OR', 'C'],
 [['A', 'AND', 'B'], 'AND', 'D'],
 [['A', 'AND', 'B'], 'OR', 'D'],
 [['A', 'OR', 'B'], 'AND', 'D'],
 [['A', 'OR', 'B'], 'OR', 'D'],
 [['A', 'AND', 'C'], 'AND', 'D'],
 [['A', 'AND', 'C'], 'OR', 'D'],
 [['A', 'OR', 'C'], 'AND', 'D'],
 [['A', 'OR', 'C'], 'OR', 'D'],
 [['B', 'AND', 'C'], 'AND', 'D'],
 [['B', 'AND', 'C'], 'OR', 'D'],
 [['B', 'OR', 'C'], 'AND', 'D'],
 [['B', 'OR', 'C'], 'OR', 'D']]