Je voudrais paire itertools.cycle
avec zip
:
import itertools
def circular_pairwise(l):
second = itertools.cycle(l)
next(second)
return zip(l, second)
cycle
renvoie un objet iterable qui donne les valeurs de ses arguments, en boucle à partir de la dernière valeur de la première.
Nous sauter à la première valeur, de sorte qu'il commence à la position 1
(plutôt que d' 0
).
Ensuite, nous avons zip
avec l'original, non mutée liste. zip
est bon, parce qu'il s'arrête lorsque l'un de ses argument iterables sont épuisées.
Cette façon de faire permet d'éviter la création de tout intermédiaire des listes: cycle
contient une référence à l'original, mais ne copie pas. zip
fonctionne de la même façon.
Il est important de noter que cela va se briser si l'entrée est un iterator
, comme un file
, (ou un map
ou zip
en python-3), au titre de l'avancement dans un seul endroit (par next(second)
) seront automatiquement l'avance l'itérateur à tous les autres. Ceci est facilement résolu en utilisant itertools.tee
, ce qui produit deux fonctionnant indépendamment des itérateurs sur l'original itératif:
def circular_pairwise(it):
first, snd = itertools.tee(it)
second = itertools.cycle(snd)
next(second)
return zip(first, second)
tee
peut utiliser de grandes quantités d'espace de stockage supplémentaire, par exemple, si l'un des retournés itérateurs est utilisé avant l'autre est touché, mais comme nous ne jamais l'un de l'étape de la différence, le stockage supplémentaire est minime.