我在论坛上发过类似帖子,但他们都建议使用itertools.product
,但我想知道是否可以在不使用它的情况下解决。
我想打印N个硬币的所有结果组合。如果事先知道N,则可以这样做。所以嵌套循环的数量只是N.但是如果N必须动态确定(input()
函数),那么我就不能在代码中实现它了。用简单的英语很容易想象for循环的数量与N成正比,但我该如何实现呢?我必须使用lambda或递归吗?以下是N = 4的示例代码。
results = ["H", "T"]
outcomes = []
for l1 in results:
for l2 in results:
for l3 in results:
for l4 in results:
outcomes.append(l1+l2+l3+l4)
for o in outcomes:
print(o)
提前致谢。
答案 0 :(得分:3)
DIY与发电机
这是在不使用内置功能的情况下计算product
列表的一种方法
def product (*iters):
def loop (prod, first = [], *rest):
if not rest:
for x in first:
yield prod + (x,)
else:
for x in first:
yield from loop (prod + (x,), *rest)
yield from loop ((), *iters)
for prod in product ("ab", "xyz"):
print (prod)
# ('a', 'x')
# ('a', 'y')
# ('a', 'z')
# ('b', 'x')
# ('b', 'y')
# ('b', 'z')
在python中,我们可以使用list
构造函数收集列表中生成器的输出。请注意,我们还可以计算两个以上输入的乘积,如下所示
print (list (product ("+-", "ab", "xyz")))
# [ ('+', 'a', 'x')
# , ('+', 'a', 'y')
# , ('+', 'a', 'z')
# , ('+', 'b', 'x')
# , ('+', 'b', 'y')
# , ('+', 'b', 'z')
# , ('-', 'a', 'x')
# , ('-', 'a', 'y')
# , ('-', 'a', 'z')
# , ('-', 'b', 'x')
# , ('-', 'b', 'y')
# , ('-', 'b', 'z')
# ]
由于product
接受 iterables 的列表,因此可以在产品中使用任何可迭代的输入。它们甚至可以混合,如下所示
print (list (product (['@', '%'], range (2), "xy")))
# [ ('@', 0, 'x')
# , ('@', 0, 'y')
# , ('@', 1, 'x')
# , ('@', 1, 'y')
# , ('%', 0, 'x')
# , ('%', 0, 'y')
# , ('%', 1, 'x')
# , ('%', 1, 'y')
# ]
由于product
被定义为生成器,因此即使编写更复杂的程序,我们也可以获得很大的灵活性。考虑这个程序,找到由整数组成的直角三角形Pythagorean triple。另请注意,product
允许您重复可迭代作为输入,如下面的product (r, r, r)
所示
def is_triple (a, b, c):
return a * a + b * b == c * c
def solver (n):
r = range (1, n)
for p in product (r, r, r):
if is_triple (*p):
yield p
print (list (solver (20)))
# (3, 4, 5)
# (4, 3, 5)
# (5, 12, 13)
# (6, 8, 10)
# (8, 6, 10)
# (8, 15, 17)
# (9, 12, 15)
# (12, 5, 13)
# (12, 9, 15)
# (15, 8, 17)
现在很容易实现你的掷硬币计划。
def toss_coins (n):
sides = [ 'H', 'T' ]
coins = [ sides ] * n
yield from product (*coins)
print (list (toss_coins (2)))
# [ ('H', 'H'), ('H', 'T'), ('T', 'H'), ('T', 'T') ]
print (list (toss_coins (3)))
# [ ('H', 'H', 'H'), ('H', 'H', 'T'), ('H', 'T', 'H'), ('H', 'T', 'T'), ('T', 'H', 'H'), ('T', 'H', 'T'), ('T', 'T', 'H'), ('T', 'T', 'T') ]
没有发电机
但是生成器是一种非常高级的语言特性,我们想知道如何使用纯递归来表示product
。 product
以下def map (f, lst):
if not lst:
return []
else:
first, *rest = lst
return [ f (first ) ] + map (f, rest)
def flat_map (f, lst):
if not lst:
return []
else:
first, *rest = lst
return f (first) + flat_map (f, rest)
def product (*iters):
def loop (acc, iters):
if not iters:
return acc
else:
first, *rest = iters
return flat_map (lambda c: map (lambda x: [x] + c, first), loop (acc, rest))
return loop ([[]], iters)
重新实现,不使用生成器,现在返回一个包含所有计算子产品的填充数组
yield
我们现在可以跳过您计划中的list
和def toss_coins (n):
sides = [ 'H', 'T' ]
coins = [ sides ] * n
return product (*coins)
print (toss_coins (2))
# [('H', 'H'), ('H', 'T'), ('T', 'H'), ('T', 'T')]
print (toss_coins (3))
# [('H', 'H', 'H'), ('H', 'H', 'T'), ('H', 'T', 'H'), ('H', 'T', 'T'), ('T', 'H', 'H'), ('T', 'H', 'T'), ('T', 'T', 'H'), ('T', 'T', 'T')]
来电
map
上面,我们定义flat_map
和reduce
尽可能少的依赖关系,但每个实现中只有一个细微的区别。下面,我们将每个代表为 fold (使用map
),以便我们更容易地看到语义差异。另请注意,Python包含自己的reduce
和functools
版本(def concat (xs, ys):
return xs + ys
def append (xs, x):
return xs + [ x ]
def reduce (f, init, lst):
if not lst:
return init
else:
first, *rest = lst
return reduce (f, f (init, first), rest)
def map_reduce (m, r):
return lambda acc, x: r (acc, m (x))
def map (f, lst):
return reduce (map_reduce (f, append), [], lst)
def flat_map (f, lst):
return reduce (map_reduce (f, concat), [], lst)
def product (*iters):
# this stays the same
),与此处提供的版本略有不同。
String uint64ToString(uint64_t input) {
String result = "";
uint8_t base = 10;
do {
char c = input % base;
input /= base;
if (c < 10)
c +='0';
else
c += 'A' - 10;
result = c + result;
} while (input);
return result;
}