挑战:在元组的每个位置创建具有不同值 'options' 的不同组合的元组列表。
Challenge: Creating a list of tuples of different combinations with different value 'options' in each location of the tuple.
挑战来了。如果你能解决它,你就是一个比我更好的人。
假设 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 会给出(无特定顺序)
[(1,1,1,1),(1,1,2,0),(1,1,0,2),(0,0,2,2),(0,0,0,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))
但是就像我说的那样创建所有组合所以使用它可以减少它是作弊。
你可以使用 a list comprehension with short-circuiting conditionals:
[(a,b,c,d)
for a in range(2)
for b in range(2)
if a+b <= 4
for c in range(3)
if a+b+c <= 4
for d in [0,1,2,4]
if a+b+c+d == 4]
产量
[(0, 0, 0, 4),
(0, 0, 2, 2),
(0, 1, 1, 2),
(0, 1, 2, 1),
(1, 0, 1, 2),
(1, 0, 2, 1),
(1, 1, 0, 2),
(1, 1, 1, 1),
(1, 1, 2, 0)]
这会找到所有解,而无需枚举整组笛卡尔
产品。一旦部分和大于
目标金额。
将其概括为可以接受任意集合的函数
从中形成笛卡尔积的迭代器,我们可以使用
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,)
主要区别在于它使用条件 if y == target
将产生的项目限制为总和等于 target
.
的项目
它类似于this pure-Python implementation shown in the docs,只是它在生成项目之前不生成所有产品。
例如,constrained_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-statement
:
来加速代码
for y in pools[-1]:
if target-y >= 0:
for x in constrained_product(target-y, *pools[:-1]):
yield x + (y,)
如果 target-y < 0
那么调用 constrained_product(target-y,
*pools[:-1])
是没有意义的,因为根据假设 pools[:-1]
中的所有值都是
非负数。我们知道没有可以求和为负数的元组,所以
我们可以通过删除此分支来节省时间。
使用 constrained_product
、
的修改版本
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
挑战来了。如果你能解决它,你就是一个比我更好的人。 假设 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 会给出(无特定顺序)
[(1,1,1,1),(1,1,2,0),(1,1,0,2),(0,0,2,2),(0,0,0,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))
但是就像我说的那样创建所有组合所以使用它可以减少它是作弊。
你可以使用 a list comprehension with short-circuiting conditionals:
[(a,b,c,d)
for a in range(2)
for b in range(2)
if a+b <= 4
for c in range(3)
if a+b+c <= 4
for d in [0,1,2,4]
if a+b+c+d == 4]
产量
[(0, 0, 0, 4),
(0, 0, 2, 2),
(0, 1, 1, 2),
(0, 1, 2, 1),
(1, 0, 1, 2),
(1, 0, 2, 1),
(1, 1, 0, 2),
(1, 1, 1, 1),
(1, 1, 2, 0)]
这会找到所有解,而无需枚举整组笛卡尔 产品。一旦部分和大于 目标金额。
将其概括为可以接受任意集合的函数 从中形成笛卡尔积的迭代器,我们可以使用
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,)
主要区别在于它使用条件 if y == target
将产生的项目限制为总和等于 target
.
它类似于this pure-Python implementation shown in the docs,只是它在生成项目之前不生成所有产品。
例如,constrained_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-statement
:
for y in pools[-1]:
if target-y >= 0:
for x in constrained_product(target-y, *pools[:-1]):
yield x + (y,)
如果 target-y < 0
那么调用 constrained_product(target-y,
*pools[:-1])
是没有意义的,因为根据假设 pools[:-1]
中的所有值都是
非负数。我们知道没有可以求和为负数的元组,所以
我们可以通过删除此分支来节省时间。
使用 constrained_product
、
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