提问人:oskros 提问时间:9/5/2023 更新时间:9/6/2023 访问量:62
使用 yield 将列表函数转换为生成器
Converting list function to generator using yield
问:
我正在尝试使用 yield 将 for 循环转换为迭代器,但我的尝试失败了。我不明白为什么没有给我预期的输出。有谁知道问题出在哪里?yield
尝试使用产量:
def iteration_order(dimensions):
for dim in range(dimensions):
order = [0, dim, 0]
yield order
for j in range(6):
sgn = 1 if j % 2 == 0 else -1
idx = j % 3
for _ in range(dim if j < 5 else dim-1):
order[idx] += sgn
yield order
print(list(iteration_order(2))
>>> [[0, 0, 0], [0, 1, 1], [0, 1, 1], [0, 1, 1], [0, 1, 1], [0, 1, 1], [0, 1, 1]]
代码应该起作用(不使用 yield 时):
def iteration_order(dimensions):
full_order = []
for dim in range(dimensions):
order = [[0, dim, 0]]
for j in range(6):
sgn = 1 if j % 2 == 0 else -1
idx = j % 3
for _ in range(dim if j < 5 else dim-1):
nxt = list(order[-1])
nxt[idx] += sgn
order.append(nxt)
full_order.extend(order)
return full_order
print(iteration_order(2))
>>> [[0, 0, 0], [0, 1, 0], [1, 1, 0], [1, 0, 0], [1, 0, 1], [0, 0, 1], [0, 1, 1]]
答:
1赞
Andrej Kesely
9/5/2023
#1
IIUC,您可以做到:
def iteration_order(dimensions):
for dim in range(dimensions):
order = [[0, dim, 0]]
for j in range(6):
sgn = 1 if j % 2 == 0 else -1
idx = j % 3
for _ in range(dim if j < 5 else dim - 1):
nxt = list(order[-1])
nxt[idx] += sgn
order.append(nxt)
yield from order # <-- yield from
print(list(iteration_order(2)))
指纹:
[[0, 0, 0], [0, 1, 0], [1, 1, 0], [1, 0, 0], [1, 0, 1], [0, 0, 1], [0, 1, 1]]
评论
0赞
matszwecja
9/5/2023
这难道不会通过立即计算一切来破坏发电机的目的吗?
0赞
oskros
9/5/2023
我想这部分解决了这个问题,因为只计算当前维度值然后生成,而不是最初计算所有内容 - 但这不是一个完美的解决方案
2赞
Matt Pitkin
9/5/2023
#2
您需要随时复制列表,例如,
def iteration_order(dimensions):
for dim in range(dimensions):
order = [0, dim, 0]
yield order
corder = list(order) # copy original list
for j in range(6):
sgn = 1 if j % 2 == 0 else -1
idx = j % 3
corder = list(corder) # copy updated list
for _ in range(dim if j < 5 else dim-1):
corder[idx] += sgn
yield corder
这给出了:
print(list(iteration_order(2)))
[[0, 0, 0], [0, 1, 0], [1, 1, 0], [1, 0, 0], [1, 0, 1], [0, 0, 1], [0, 1, 1]]
不出所料。
2赞
matszwecja
9/5/2023
#3
您看到的问题是因为您对所有内容都使用相同的列表。您可能会生成具有不同值的值,但生成器仍然引用了该列表并对其进行了修改,从而为您提供了奇怪的输出。如果为每个产量添加,它们将是唯一的列表,并且将按预期运行:.copy()
def iteration_order(dimensions):
for dim in range(dimensions):
order = [0, dim, 0]
yield order.copy()
for j in range(6):
sgn = 1 if j % 2 == 0 else -1
idx = j % 3
for _ in range(dim if j < 5 else dim-1):
order[idx] += sgn
yield order.copy()
print(list(iteration_order(2))) # [[0, 0, 0], [0, 1, 0], [1, 1, 0], [1, 0, 0], [1, 0, 1], [0, 0, 1], [0, 1, 1]]
1赞
JonSG
9/5/2023
#4
我认为问题在于,你产生了一些尚未“完成”的东西,而这个东西是可以修改的。
退房:
def iteration_order(dimensions):
for dim in range(dimensions):
order = [0, dim, 0]
yield order
for j in range(6):
sgn = 1 if j % 2 == 0 else -1
idx = j % 3
for _ in range(dim if j < 5 else dim-1):
order[idx] += sgn
yield order
bar = []
for x in iteration_order(2):
print(x)
bar.append(x)
print(bar)
导致...
[0, 0, 0]
[0, 1, 0]
[1, 1, 0]
[1, 0, 0]
[1, 0, 1]
[0, 0, 1]
[0, 1, 1]
[[0, 0, 0], [0, 1, 1], [0, 1, 1], [0, 1, 1], [0, 1, 1], [0, 1, 1], [0, 1, 1]]
你期望结果基本相同吗?然而,它们不是,因为最里面的循环在产生它后并没有“完成”。最简单的解决方法是生成副本。for
order
def iteration_order(dimensions):
for dim in range(dimensions):
order = [0, dim, 0]
yield order.copy()
for j in range(6):
sgn = 1 if j % 2 == 0 else -1
idx = j % 3
for _ in range(dim if j < 5 else dim-1):
order[idx] += sgn
yield order.copy()
给你:
[0, 0, 0]
[0, 1, 0]
[1, 1, 0]
[1, 0, 0]
[1, 0, 1]
[0, 0, 1]
[0, 1, 1]
[[0, 0, 0], [0, 1, 0], [1, 1, 0], [1, 0, 0], [1, 0, 1], [0, 0, 1], [0, 1, 1]]
评论
1赞
oskros
9/6/2023
当然,屈服时没有考虑过列表的修改。我什至在原始函数中对此进行了修复。谢谢
1赞
trincot
9/6/2023
#5
正如其他人所指出的,您需要避免改变已经生成的列表;所以产生副本。
不相关,但如果你避免在内部循环中表达式,并且总是进行迭代,可以说它更优雅。将例外情况移到开头 -- 产生 [0,0,0],但 is 为零时除外:if...else
range
dim
dimensions
def iteration_order(dimensions):
order = [0, 0, 0]
if dimensions:
yield order[:] # Now this is the exceptional case
for dim in range(1, dimensions):
order[1] = dim
for j in range(6):
sgn = -(j % 2) or 1
idx = j % 3
for _ in range(dim):
yield order[:]
order[idx] += sgn
评论
1赞
oskros
9/6/2023
非常优雅!将第一个收益移到开头确实简化了很多。标志评估也很出色 - 非常感谢
评论
hex_array=np.zeros((dims*2,dims*2))
i=0; for order in iteration_order(dims): hex_array[dims+ordr[0]-ordr[2], dims+ordr[1]-ordr[0]] = i; i += 1