我正在尝试接受一个生成器,其中每个元素都是list / tuple / iterable,它们具有相同的长度,并为元素的每个索引返回一个单独的生成器。
当我在下面的split_feat2
中对索引进行硬编码时,它按预期工作。但是,当我使用列表推导或附加到列表并返回它时会产生不正确的结果。
我检查了我的逻辑并尝试通过在理解中用()
代替[]
来返回列表而不是生成器列表,并且它产生了正确的结果,因此我不知道问题出在哪里是
非常感谢任何有关它为何如此行事的见解。
def split_feat2(gen):
G = tee(gen, 2)
return [(e[0] for e in G[0]), (e[1] for e in G[1])]
def split_feat(gen, n):
G = tee(gen, n)
return [(e[n] for e in g) for n, g in enumerate(G)]
def split_featlist(gen, n):
G = tee(gen, n)
return [[e[n] for e in g] for n, g in enumerate(G)]
test = lambda:((i^2,j+i) for i, j in enumerate(range(10)))
print("This is what I want")
t = split_feat2(test())
print(list(t[0]))
print(list(t[1]))
print(t)
print("\nBut I get this output")
t = split_feat(test(), 2)
print(list(t[0]))
print(list(t[1]))
print(t)
print("\nWhen I want this output but from generators instead of lists")
t = split_featlist(test(), 2)
print(list(t[0]))
print(list(t[1]))
print(t)
以上代码输出如下:
This is what I want
[2, 3, 0, 1, 6, 7, 4, 5, 10, 11]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
[<generator object split_feat2.<locals>.<genexpr> at 0x00000219C794F7D8>, <generator object split_feat2.<locals>.<genexpr> at 0x00000219C794F200>]
But I get this output
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
[<generator object split_feat.<locals>.<listcomp>.<genexpr> at 0x00000219C791DB48>, <generator object split_feat.<locals>.<listcomp>.<genexpr> at 0x00000219C794F150>]
When I want this output but from generators instead of lists
[2, 3, 0, 1, 6, 7, 4, 5, 10, 11]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
[[2, 3, 0, 1, 6, 7, 4, 5, 10, 11], [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]]
答案 0 :(得分:1)
问题是在实际使用生成器之前n
变量已更改。因此,当函数返回n - 1
处的生成器列表时(函数参数n
)。因此,在您的示例中,两个生成器都使用相同的索引:1
。要了解我的意思,请看这个简单的例子:
>>> list_of_list = [[0, 1]]*20
>>> index = 1
>>> gen = (item[index] for item in list_of_list)
>>> print(next(gen))
1
>>> index = 0
>>> print(next(gen)) # changing index "changed the generator"
0
在你的情况下,循环不断变化n
(不像我的例子中的手动干预),但是当生成器被执行时,它对于所有创建的生成器都是固定的,具有相同的值。
你需要&#34;修复&#34;每次迭代以某种方式的n
的当前值。一种可能性是map
operator.itemgetter
:
def split_feat(gen, n):
G = tee(gen, n)
return [map(itemgetter(n), g) for n, g in enumerate(G)]
itemgetter
立即创建了&#34;当前&#34; n
值,因此结果将符合预期。
这不是实现预期结果的唯一方法。您还可以使用创建生成器的函数。该功能将记住&#34;当前的n
(就像一个闭包),也像你期望的那样工作:
def split_feat(gen, n):
G = tee(gen, n)
def create_generator(it, n):
return (item[n] for item in it)
return [create_generator(g, n) for n, g in enumerate(G)]