Python 2.7 挑战:创建具有不同值的不同组合的元组列表';选项';在元组的每个位置。

Python 2.7 挑战:创建具有不同值的不同组合的元组列表';选项';在元组的每个位置。,python-2.7,combinations,Python 2.7,Combinations,这就是挑战。如果你能解决这个问题,你就比我强。 假设a can=1或0,b can=1或0,c can=0,1或2,d can=0,1,2或4,e仅为0,f=0或1 列出一个元组列表,其中所有组合的总和为特定数字,小于5,用于选择字母 例如a、b、c、d和数字4(无特定顺序) 或者f,f,e,d,c和3会给出 [(1,1,0,1,0),(1,1,0,0,1)(1,0,0,1,1),(1,0,0,2,0),(1,0,0,0,2),(0,1,0,2,0),(0,1,0,0,2)] 创建所有的组合,

这就是挑战。如果你能解决这个问题,你就比我强。 假设a can=1或0,b can=1或0,c can=0,1或2,d can=0,1,2或4,e仅为0,f=0或1

列出一个元组列表,其中所有组合的总和为特定数字,小于5,用于选择字母

例如a、b、c、d和数字4(无特定顺序)

或者f,f,e,d,c和3会给出

[(1,1,0,1,0),(1,1,0,0,1)(1,0,0,1,1),(1,0,0,2,0),(1,0,0,0,2),(0,1,0,2,0),(0,1,0,0,2)]
创建所有的组合,然后删除那些不符合数字的组合,这是欺骗,效率太低

我试过使用

list(itertools.product(*a))
但就像我说的那样,它创造了所有的组合,所以使用它可以减少它是欺骗。

你可以使用:

这将查找所有解决方案,而无需枚举整个笛卡尔函数集 产品。只要部分和大于最大值,它就会短路 目标金额


将其推广到可以接受任意 我们可以使用它来形成笛卡尔积

def constrained_product(target, *args):
    pools = map(tuple, args)
    if len(pools) == 1:
        for y in pools[0]:
            if y == target:
                yield (y,)
    else:
        for y in pools[-1]:
            for x in constrained_product(target-y, *pools[:-1]):
                yield x + (y,)
这是这个纯Python实现的一个稍加修改的版本
itertools.product

def iterproduct(*args):
    """
    list(iterproduct('ABCD', 'xy')) --> Ax Ay Bx By Cx Cy Dx Dy
    """
    pools = map(tuple, args)
    if len(pools) == 1:
        for y in pools[0]:
            yield (y,)
    else:
        for x in iterproduct(*pools[:-1]):
            for y in pools[-1]:
                yield x + (y,)
主要区别在于,如果y==target 将生成的项目约束为总和等于
target
的项目

它与类似,只是在生成项目之前不会生成所有产品


例如,
constrated\u product
可以这样使用:

A = range(2)
B = range(2)
C = range(3)
D = [0,1,2,4]
E = [0]
F = range(2)

def constrained_product(target, *args):
    pools = map(tuple, args)
    if len(pools) == 1:
        for y in pools[0]:
            if y == target:
                yield (y,)
    else:
        for y in pools[-1]:
            for x in constrained_product(target-y, *pools[:-1]):
                yield x + (y,)

for item in constrained_product(4, A, B, C, D):
    print(item)
    # (1, 1, 2, 0)
    # (1, 1, 1, 1)
    # (1, 0, 2, 1)
    # (0, 1, 2, 1)
    # (1, 1, 0, 2)
    # (1, 0, 1, 2)
    # (0, 1, 1, 2)
    # (0, 0, 2, 2)
    # (0, 0, 0, 4)

for item in constrained_product(3, F, F, E, D, C):
    print(item)
    # (1, 1, 0, 1, 0)
    # (1, 0, 0, 2, 0)
    # (0, 1, 0, 2, 0)
    # (1, 1, 0, 0, 1)
    # (1, 0, 0, 1, 1)
    # (0, 1, 0, 1, 1)
    # (0, 0, 0, 2, 1)
    # (1, 0, 0, 0, 2)
    # (0, 1, 0, 0, 2)
    # (0, 0, 0, 1, 2)

如果我们可以还假设
args
中的值都是非负的 然后,我们可以通过添加
if语句
,来加快代码的速度:

    for y in pools[-1]:
        if target-y >= 0:
            for x in constrained_product(target-y, *pools[:-1]):
                yield x + (y,)
如果
target-y<0
则调用
约束的_产品(target-y,
*池[:-1])
因为根据假设,
池[:-1]
中的所有值都是 非负。我们知道没有可以和为负数的元组,所以 我们可以去掉这根树枝来节省时间

使用此修改版本的
受约束的\u产品

def constrained_product_nonneg(target, *args):
    pools = map(tuple, args)
    if len(pools) == 1:
        for y in pools[0]:
            if y == target:
                yield (y,)
    else:
        for y in pools[-1]:
            if target-y >= 0:
                for x in constrained_product_nonneg(target-y, *pools[:-1]):
                    yield x + (y,)
现在

快速找到解决方案:

In [35]: %timeit list(constrained_product_nonneg(0, *[A]*53))
10000 loops, best of 3: 170 µs per loop

这是一个基于树的解决方案。它为系统提供了所有有效的答案(这可能是作弊),但它不必重复计算

class tree_node:
     def __init__(self, v, s, p):
          self.value = v
          self.sum = s
          self.parent = p
          self.branchList = []

if __name__ == "__main__":

    # Initialize the tree. The sums will be in the leaves once it's built
    root = tree_node(None, 0, None)
    leaf_list = [root]

    # Define the rules of the problem
    a = [0, 1]
    b = [0, 1]
    c = [0, 1, 2]
    d = [0, 1, 4]
    e = [0]
    f = [0, 1]
    rules = [a, b, c, d, e, f]

    # Build the tree, one layer of nodes at a time
    for rule in rules:
       new_leaves = []
       for leaf in leaf_list:
           for r in rule:
                tn = tree_node(r, r + leaf.sum, leaf)
                new_leaves.append(tn)
       leaf_list = new_leaves


    # Traverse the tree starting from each matching leaf
    target = 4
    for n in leaf_list:
        if n.sum == target:
            sequence = [n.value]
            parent = n.parent
            while parent.value != None:
                sequence = sequence + [parent.value]
                parent = parent.parent
            sequence.reverse()
            print sequence

如果我错了,请告诉我这真的很接近,但是当我运行它时,输出给我len()=7的列表,因为规则中只有6个字母,我不确定它是否正确。你是对的。它考虑的是根节点,这不是规则的一部分。现在应该修好了。你排在倒数第二,这真是太棒了。我将约束_产品(4,A,B,C,D)中的“for item:”部分更改为约束_产品(4,A,B,C,D)中的项的x=[]:x.append(item),以便将其输出到列表中。你认为这样做有什么问题吗?然而,像“0、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A”这样的东西,似乎需要很长时间,因为它只需要(0、0、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A、A,
C
s是否只包含非负数?如果是这样的话,代码可以进一步加速。@HappyleAppSecond yes,A,B,C将只包含0,1,2,3,4。此外,如果您将“目标”设置为4,并计算目标0,1,2,3,4,则更容易/更快。关于第一条注释中的Q:您可以使用
x=list(受约束产品(4,A,B,C,D))
而不是
x=[]。。。;x、 附加(项目)
def constrained_product_nonneg(target, *args):
    pools = map(tuple, args)
    if len(pools) == 1:
        for y in pools[0]:
            if y == target:
                yield (y,)
    else:
        for y in pools[-1]:
            if target-y >= 0:
                for x in constrained_product_nonneg(target-y, *pools[:-1]):
                    yield x + (y,)
list(constrained_product_nonneg(0, *[A]*53))
In [35]: %timeit list(constrained_product_nonneg(0, *[A]*53))
10000 loops, best of 3: 170 µs per loop
class tree_node:
     def __init__(self, v, s, p):
          self.value = v
          self.sum = s
          self.parent = p
          self.branchList = []

if __name__ == "__main__":

    # Initialize the tree. The sums will be in the leaves once it's built
    root = tree_node(None, 0, None)
    leaf_list = [root]

    # Define the rules of the problem
    a = [0, 1]
    b = [0, 1]
    c = [0, 1, 2]
    d = [0, 1, 4]
    e = [0]
    f = [0, 1]
    rules = [a, b, c, d, e, f]

    # Build the tree, one layer of nodes at a time
    for rule in rules:
       new_leaves = []
       for leaf in leaf_list:
           for r in rule:
                tn = tree_node(r, r + leaf.sum, leaf)
                new_leaves.append(tn)
       leaf_list = new_leaves


    # Traverse the tree starting from each matching leaf
    target = 4
    for n in leaf_list:
        if n.sum == target:
            sequence = [n.value]
            parent = n.parent
            while parent.value != None:
                sequence = sequence + [parent.value]
                parent = parent.parent
            sequence.reverse()
            print sequence