【问题标题】:list comprehension variable assignment [duplicate]列表理解变量赋值
【发布时间】:2019-03-16 18:05:51
【问题描述】:

我正在尝试创建一个 4d 数组并将变量分配给每个单元格。

通常我会使用四个“for 循环”,但这非常混乱且占用大量空间。

我现在在做什么:

for x in range(2):
    for y in range(2):
        for j in range(2):
            for k in range(2):
                array[x,y,j,k] = 1 #will be a function in reality

我尝试过使用列表推导,但这只会创建列表并且不会为每个单元格分配变量。

是否有节省空间的方法来运行多个 for 循环并只用几行代码分配变量?

【问题讨论】:

  • “我尝试过使用列表推导,但这只会创建列表并且不会为每个单元格分配变量。” - 列表推导可以完成您的四重嵌套循环所做的一切。要么你搞砸了你的理解,要么你不太明白你的循环在做什么。
  • 当你说“数组”时,你到底是什么意思?一个numpy数组?列表列表?
  • 列表推导适用于 列表array 似乎是一个 NumPy 数组(或者可能是一个 dict)。
  • 据我所知,列表理解主要用于初始化列表,但不用于将变量分配给列表索引——我对他的看法有误吗?
  • 列表推导用于创建新列表,是的。

标签: python loops list-comprehension nested-loops


【解决方案1】:

假设您已经创建了一个空(numpy?)数组,您可以使用itertools.product 来填充它:

import itertools

for x, y, j, k in itertools.product(range(2), repeat=4):
    arr[x,y,j,k] = 1

如果不是所有数组的维度都相等,您可以单独列出它们:

for x, y, j, k in itertools.product(range(2), range(2), range(2), range(2)):
    arr[x,y,j,k] = 1

【讨论】:

  • 这正是我要找的!我已经搜索了很久才能找到这个答案!出于好奇,这实际上是称为列表理解还是其他什么?
  • numpy.indices() 会不会更合适?
  • 另外,numpy 数组可以直接迭代 complete with indices and a writeable reference.
  • @MartijnPieters 好吧,我不确定它是否真的是一个 numpy 数组,所以...
【解决方案2】:

但是,您可能想知道 itertools.product 是如何做到的。或者,也许您想在递归扩展中编码不同的转换。下面,我将分享一种可能的解决方案,使用 Python 的生成器 -

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')

因为product 接受iterables 的列表,所以产品中可以使用任何可迭代的输入。它们甚至可以像这里演示的那样混合 -

print (list (product (['@', '%'], range (2), "xy")))
# [ ('@', 0, 'x')
# , ('@', 0, 'y')
# , ('@', 1, 'x')
# , ('@', 1, 'y')
# , ('%', 0, 'x')
# , ('%', 0, 'y')
# , ('%', 1, 'x')
# , ('%', 1, 'y')
# ]

我们可以制作一个程序 foo 来提供您问题中发布的输出 -

def foo (n, m):
  ranges = [ range (m) ] * n
  yield from product (*ranges)

for prod in foo (4, 2):
  print (prod)

# (0, 0, 0, 0)
# (0, 0, 0, 1)
# (0, 0, 1, 0)
# (0, 0, 1, 1)
# (0, 1, 0, 0)
# (0, 1, 0, 1)
# (0, 1, 1, 0)
# (0, 1, 1, 1)
# (1, 0, 0, 0)
# (1, 0, 0, 1)
# (1, 0, 1, 0)
# (1, 0, 1, 1)
# (1, 1, 0, 0)
# (1, 1, 0, 1)
# (1, 1, 1, 0)
# (1, 1, 1, 1)

或者使用解构赋值为产品的各个元素创建绑定。在您的程序中,只需将 print 替换为您的实际功能 -

for (w, x, y, z) in foo (4, 2):
  print ("w", w, "x", x, "y", y, "z", z)

# w 0 x 0 y 0 z 0
# w 0 x 0 y 0 z 1
# w 0 x 0 y 1 z 0
# w 0 x 0 y 1 z 1
# w 0 x 1 y 0 z 0
# w 0 x 1 y 0 z 1
# w 0 x 1 y 1 z 0
# w 0 x 1 y 1 z 1
# w 1 x 0 y 0 z 0
# w 1 x 0 y 0 z 1
# w 1 x 0 y 1 z 0
# w 1 x 0 y 1 z 1
# w 1 x 1 y 0 z 0
# w 1 x 1 y 0 z 1
# w 1 x 1 y 1 z 0
# w 1 x 1 y 1 z 1

因为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)

如需更多解释以及如何在不使用生成器的情况下执行此操作,请查看this answer

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多