Je veux analyser 2 générateurs de longueur (potentiellement) différente avec Zip
:
for el1, el2 in Zip(gen1, gen2):
print(el1, el2)
Toutefois, si gen2
a moins d'éléments, un élément supplémentaire de gen1
est "consommé".
Par exemple,
def my_gen(n:int):
for i in range(n):
yield i
gen1 = my_gen(10)
gen2 = my_gen(8)
list(Zip(gen1, gen2)) # Last Tuple is (7, 7)
print(next(gen1)) # printed value is "9" => 8 is missing
gen1 = my_gen(8)
gen2 = my_gen(10)
list(Zip(gen1, gen2)) # Last Tuple is (7, 7)
print(next(gen2)) # printed value is "8" => OK
Apparemment, il manque une valeur (8
dans mon exemple précédent) parce que gen1
est lu (générant ainsi la valeur 8
) avant de réaliser gen2
n'a plus d'éléments. Mais cette valeur disparaît dans l'univers. Quand gen2
est "plus", il n'y a pas de "problème".
[~ # ~] question [~ # ~] : existe-t-il un moyen de récupérer cette valeur manquante (c'est-à-dire 8
dans mon exemple précédent)? ... idéalement avec un nombre variable d'arguments (comme Zip
le fait).
[~ # ~] note [~ # ~]: J'ai actuellement implémenté d'une autre manière en utilisant itertools.Zip_longest
mais je me demande vraiment comment obtenir cette valeur manquante en utilisant Zip
ou équivalent.
NOTE 2: J'ai créé quelques tests des différentes implémentations dans ce REPL au cas où vous voudriez soumettre et essayer une nouvelle implémentation :) https://repl.it/@jfthuong/MadPhysicistChester
Si vous souhaitez réutiliser du code, la solution la plus simple est:
from more_itertools import peekable
a = peekable(a)
b = peekable(b)
while True:
try:
a.peek()
b.peek()
except StopIteration:
break
x = next(a)
y = next(b)
print(x, y)
print(list(a), list(b)) # Misses nothing.
Vous pouvez tester ce code en utilisant votre configuration:
def my_gen(n: int):
yield from range(n)
a = my_gen(10)
b = my_gen(8)
Il imprimera:
0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
[8, 9] []
je ne pense pas que vous puissiez récupérer la valeur supprimée avec la boucle for de base, car l'itérateur épuisé, extrait de Zip(..., ...).__iter__
, est supprimé une fois épuisé et vous ne pouvez pas y accéder.
Vous devez faire muter votre Zip, vous pouvez alors obtenir la position de l'élément déposé avec du code hacky)
z = Zip(range(10), range(8))
for _ in iter(z.__next__, None):
...
_, (one, other) = z.__reduce__()
_, (i_one,), p_one = one.__reduce__() # p_one == current pos, 1 based
import itertools
val = next(itertools.islice(iter(i_one), p_one - 1, p_one))