将此映射转换为 for 语句
Converting this map into a for statement
将以下 map
语句正确转换为 for
循环的正确方法是什么?
map(lambda x: map(lambda y: map(lambda z: x*y*z, [5,6]), [3,4]), [1,2])
# [[[15, 18], [20, 24]], [[30, 36], [40, 48]]]
我的第一次尝试是这样的:
x_tmp = []
for x in [1,2]:
y_tmp = []
for y in [3,4]:
z_tmp = []
for z in [5,6]:
z_tmp.append(x*y*z)
y_tmp.append(z_tmp)
x_tmp.append(y_tmp)
x_tmp
# [[[15, 18], [20, 24]], [[30, 36], [40, 48]]]
但这看起来太奇怪了,我无法想象这会是它的实际翻译。有没有更接近 map
工作原理的东西可以用 for
循环显示?
我想也许会接近:
[x*y*z for x in [1,2] for y in [3,4] for z in [5,6]]
# [15, 18, 20, 24, 30, 36, 40, 48]
但这似乎失去了所有的嵌套并改为进行平面映射。
做list-comprehension的方式看来不仅需要嵌套,而且args也需要反转,例如:
>>> [[[x*y*z for z in [5,6]] for y in [3,4]] for x in [1,2]]
# [[[15, 18], [20, 24]], [[30, 36], [40, 48]]]
您的第一次尝试确实是对嵌套 for
循环的适当转换。您最后的尝试是对嵌套列表理解的适当转换。
我不确定你为什么觉得这些不满意;展开循环通常是一件麻烦事。您刚刚以等效形式提供了一本可爱的入门书。 :-)
你可以使用递归:
def nest_op(d, p = 1):
return [nest_op(d[:-1], p*i) if d[:-1] else p*i for i in d[-1]]
print(nest_op([[5,6], [3,4], [1,2]]))
输出:
[[[15, 18], [20, 24]], [[30, 36], [40, 48]]]
不确定您使用的是哪个 REPL,但是 map
returns Python 3.
中的一个迭代器
x = map(lambda x: map(lambda y: map(lambda z: x*y*z, [5,6]), [3,4]), [1,2])
print(x)
<map object at 0x7fd6f70d1670>
您可以使用list
将迭代器转换为列表-
print(list(x))
[<map object at 0x7fd6f7034f70>, <map object at 0x7fd6f70837f0>]
如您所见,嵌套的 map
调用也会生成迭代器,因此您需要对嵌套元素调用 list
才能获得问题中的实际输出
x = list(map(lambda x: list(map(lambda y: list(map(lambda z: x*y*z, [5,6])), [3,4])), [1,2]))
print(x)
[[[15, 18], [20, 24]], [[30, 36], [40, 48]]]
你可以写一个 nested_for
接受一个 proc
和一个可变的迭代数,its
-
def nested_for(proc, *its):
def loop (acc, its):
if not its:
yield proc(*acc)
else:
for x in its[0]:
yield list(loop((*acc, x), its[1:]))
yield from loop(tuple(), its)
out = list(nested_for(lambda x,y,z: x*y*z, [1,2], [3,4], [5,6]))
print(out)
[[[[15], [18]], [[20], [24]]], [[[30], [36]], [[40], [48]]]]
此实现会产生一层额外的 [...]
嵌套。如果不希望这样,您可以使 loop
更复杂一些 -
def nested_for(proc, *its):
def loop (acc, it = None, *its):
if not it:
yield proc(*acc)
elif not its:
for v in it:
yield proc(*acc, v) # don't nest deepest iteration
else:
for v in it:
yield list(loop((*acc, v), *its))
yield from loop(tuple(), *its)
out = list(nested_for(lambda x,y,z: x*y*z, [1,2], [3,4], [5,6]))
print(out)
[[[15, 18], [20, 24]], [[30, 36], [40, 48]]]
看来你是 ,你可以简化 nested_for
使其接受咖喱 proc
-
def nested_for (proc, it = None, *its):
if not it:
return
elif not its:
for v in it:
yield proc(v)
else:
for v in it:
yield list(nested_for(proc(v), *its))
out = list(nested_for(lambda x: lambda y: lambda z: x*y*z, [1,2], [3,4], [5,6]))
print(out)
[[[15, 18], [20, 24]], [[30, 36], [40, 48]]]
除此之外,我真的不知道你想回答什么问题。正如 Prune 指出的那样,您已经确定了等效的 for
和列表理解形式。
你写
"seems to lose all the nesting and do a flat mapping instead."
这正是您最近关闭的 question 关于 Scheme code translated to Python.
的答案
(apply append (map foo xs)) == (flatmap foo xs)
和 flatmap
是嵌套 for
循环的翻译/实现方式。
明确一点:它在 [result(x,y) for x in xs for y in ys]
的意义上是嵌套的。这个问题中的嵌套列表理解,[[result for y in ys] for x in xs]
不是嵌套循环,它是一个循环 (for x in xs
) 产生整个内部列表理解的值 ([result for y in ys]
) 作为 its xs
中每个 x
的结果。
嵌套循环是组合循环,它们仅从最深的循环中产生一个序列的结果。为了用列表模拟这一点,执行 flatmap
以达到相同的效果。
所以,嵌套循环是 -- 在伪代码中,--
for x in xs:
for y in ys:
yield result(x, y)
= [result(x, y) for x in xs for y in ys]
= (flatMapOn xs (lambda (x) =>
(flatMapOn ys (lambda (y) => (list (result x y))))))
= (flatMapOn xs (lambda (x) =>
(mapOn ys (lambda (y) => (result x y) ))))
你问的“类地图”循环是
for x in xs:
yield (list (for y in ys:
yield result(x,y) ))
= [[result(x, y) for y in ys] for x in xs]
= (mapOn xs (lambda (x) =>
(mapOn ys (lambda (y) => (result x y)))))
注意,这里的外循环是 yield
,而不是 yield from
。
在Racket中我们观察
> (define (flatMapOn xs foo) (flatmap foo xs))
> (define (mapOn xs foo) (map foo xs))
> (display (flatMapOn (list 1 2 3) (lambda (x)
(flatMapOn (list x (+ x 10) (+ x 100)) (lambda (y)
(list (cons x y)))))))
((1 . 1) (1 . 11) (1 . 101) (2 . 2) (2 . 12) (2 . 102)
(3 . 3) (3 . 13) (3 . 103))
> (display (flatMapOn (list 1 2 3) (lambda (x)
(mapOn (list x (+ x 10) (+ x 100)) (lambda (y)
(cons x y))))))
((1 . 1) (1 . 11) (1 . 101) (2 . 2) (2 . 12) (2 . 102)
(3 . 3) (3 . 13) (3 . 103))
> (display (mapOn (list 1 2 3) (lambda (x)
(mapOn (list x (+ x 10) (+ x 100)) (lambda (y)
(cons x y))))))
( ((1 . 1) (1 . 11) (1 . 101))
((2 . 2) (2 . 12) (2 . 102))
((3 . 3) (3 . 13) (3 . 103)) )
将以下 map
语句正确转换为 for
循环的正确方法是什么?
map(lambda x: map(lambda y: map(lambda z: x*y*z, [5,6]), [3,4]), [1,2])
# [[[15, 18], [20, 24]], [[30, 36], [40, 48]]]
我的第一次尝试是这样的:
x_tmp = []
for x in [1,2]:
y_tmp = []
for y in [3,4]:
z_tmp = []
for z in [5,6]:
z_tmp.append(x*y*z)
y_tmp.append(z_tmp)
x_tmp.append(y_tmp)
x_tmp
# [[[15, 18], [20, 24]], [[30, 36], [40, 48]]]
但这看起来太奇怪了,我无法想象这会是它的实际翻译。有没有更接近 map
工作原理的东西可以用 for
循环显示?
我想也许会接近:
[x*y*z for x in [1,2] for y in [3,4] for z in [5,6]]
# [15, 18, 20, 24, 30, 36, 40, 48]
但这似乎失去了所有的嵌套并改为进行平面映射。
做list-comprehension的方式看来不仅需要嵌套,而且args也需要反转,例如:
>>> [[[x*y*z for z in [5,6]] for y in [3,4]] for x in [1,2]]
# [[[15, 18], [20, 24]], [[30, 36], [40, 48]]]
您的第一次尝试确实是对嵌套 for
循环的适当转换。您最后的尝试是对嵌套列表理解的适当转换。
我不确定你为什么觉得这些不满意;展开循环通常是一件麻烦事。您刚刚以等效形式提供了一本可爱的入门书。 :-)
你可以使用递归:
def nest_op(d, p = 1):
return [nest_op(d[:-1], p*i) if d[:-1] else p*i for i in d[-1]]
print(nest_op([[5,6], [3,4], [1,2]]))
输出:
[[[15, 18], [20, 24]], [[30, 36], [40, 48]]]
不确定您使用的是哪个 REPL,但是 map
returns Python 3.
x = map(lambda x: map(lambda y: map(lambda z: x*y*z, [5,6]), [3,4]), [1,2])
print(x)
<map object at 0x7fd6f70d1670>
您可以使用list
将迭代器转换为列表-
print(list(x))
[<map object at 0x7fd6f7034f70>, <map object at 0x7fd6f70837f0>]
如您所见,嵌套的 map
调用也会生成迭代器,因此您需要对嵌套元素调用 list
才能获得问题中的实际输出
x = list(map(lambda x: list(map(lambda y: list(map(lambda z: x*y*z, [5,6])), [3,4])), [1,2]))
print(x)
[[[15, 18], [20, 24]], [[30, 36], [40, 48]]]
你可以写一个 nested_for
接受一个 proc
和一个可变的迭代数,its
-
def nested_for(proc, *its):
def loop (acc, its):
if not its:
yield proc(*acc)
else:
for x in its[0]:
yield list(loop((*acc, x), its[1:]))
yield from loop(tuple(), its)
out = list(nested_for(lambda x,y,z: x*y*z, [1,2], [3,4], [5,6]))
print(out)
[[[[15], [18]], [[20], [24]]], [[[30], [36]], [[40], [48]]]]
此实现会产生一层额外的 [...]
嵌套。如果不希望这样,您可以使 loop
更复杂一些 -
def nested_for(proc, *its):
def loop (acc, it = None, *its):
if not it:
yield proc(*acc)
elif not its:
for v in it:
yield proc(*acc, v) # don't nest deepest iteration
else:
for v in it:
yield list(loop((*acc, v), *its))
yield from loop(tuple(), *its)
out = list(nested_for(lambda x,y,z: x*y*z, [1,2], [3,4], [5,6]))
print(out)
[[[15, 18], [20, 24]], [[30, 36], [40, 48]]]
看来你是 nested_for
使其接受咖喱 proc
-
def nested_for (proc, it = None, *its):
if not it:
return
elif not its:
for v in it:
yield proc(v)
else:
for v in it:
yield list(nested_for(proc(v), *its))
out = list(nested_for(lambda x: lambda y: lambda z: x*y*z, [1,2], [3,4], [5,6]))
print(out)
[[[15, 18], [20, 24]], [[30, 36], [40, 48]]]
除此之外,我真的不知道你想回答什么问题。正如 Prune 指出的那样,您已经确定了等效的 for
和列表理解形式。
你写
"seems to lose all the nesting and do a flat mapping instead."
这正是您最近关闭的 question 关于 Scheme code translated to Python.
的答案(apply append (map foo xs)) == (flatmap foo xs)
和 flatmap
是嵌套 for
循环的翻译/实现方式。
明确一点:它在 [result(x,y) for x in xs for y in ys]
的意义上是嵌套的。这个问题中的嵌套列表理解,[[result for y in ys] for x in xs]
不是嵌套循环,它是一个循环 (for x in xs
) 产生整个内部列表理解的值 ([result for y in ys]
) 作为 its xs
中每个 x
的结果。
嵌套循环是组合循环,它们仅从最深的循环中产生一个序列的结果。为了用列表模拟这一点,执行 flatmap
以达到相同的效果。
所以,嵌套循环是 -- 在伪代码中,--
for x in xs:
for y in ys:
yield result(x, y)
= [result(x, y) for x in xs for y in ys]
= (flatMapOn xs (lambda (x) =>
(flatMapOn ys (lambda (y) => (list (result x y))))))
= (flatMapOn xs (lambda (x) =>
(mapOn ys (lambda (y) => (result x y) ))))
你问的“类地图”循环是
for x in xs:
yield (list (for y in ys:
yield result(x,y) ))
= [[result(x, y) for y in ys] for x in xs]
= (mapOn xs (lambda (x) =>
(mapOn ys (lambda (y) => (result x y)))))
注意,这里的外循环是 yield
,而不是 yield from
。
在Racket中我们观察
> (define (flatMapOn xs foo) (flatmap foo xs))
> (define (mapOn xs foo) (map foo xs))
> (display (flatMapOn (list 1 2 3) (lambda (x)
(flatMapOn (list x (+ x 10) (+ x 100)) (lambda (y)
(list (cons x y)))))))
((1 . 1) (1 . 11) (1 . 101) (2 . 2) (2 . 12) (2 . 102)
(3 . 3) (3 . 13) (3 . 103))
> (display (flatMapOn (list 1 2 3) (lambda (x)
(mapOn (list x (+ x 10) (+ x 100)) (lambda (y)
(cons x y))))))
((1 . 1) (1 . 11) (1 . 101) (2 . 2) (2 . 12) (2 . 102)
(3 . 3) (3 . 13) (3 . 103))
> (display (mapOn (list 1 2 3) (lambda (x)
(mapOn (list x (+ x 10) (+ x 100)) (lambda (y)
(cons x y))))))
( ((1 . 1) (1 . 11) (1 . 101))
((2 . 2) (2 . 12) (2 . 102))
((3 . 3) (3 . 13) (3 . 103)) )