将此映射转换为 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)) )