76 votes

La circulaire Python ' pour ' boucle

Y a-t-il une belle façon Pythonique de boucle sur une liste, réaccorder une paire d’éléments ? Le dernier élément devrait être couplé avec le premier.

Si par exemple, si j’ai la liste [1, 2, 3], je souhaite obtenir les paires suivantes :

  • 1 - 2
  • 2 - 3
  • 3 - 1

112voto

J.F. Sebastian Points 102961

Un Pythonique consiste à accéder à la liste ci-dessus : `` . Pour connecter le dernier élément à la première :

49voto

g.d.d.c Points 20164

Je voudrais utiliser un `` avec `` pour y parvenir.

46voto

J'utiliserais une légère modification à l' pairwise de la recette de la itertools documentation:

def pairwise_circle(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ... (s<last>,s0)"
    a, b = itertools.tee(iterable)
    first_value = next(b, None)
    return itertools.zip_longest(a, b,fillvalue=first_value)

Ce sera tout simplement de conserver une référence à la première valeur et lors de la deuxième itérateur est épuisé, zip_longest remplira la dernière place à la première valeur.

(Notez également qu'il travaille avec des itérateurs, comme les générateurs ainsi que iterables comme les listes et les tuples.)

Notez que @Barry, la solution est très similaire à cela, mais un peu plus facile à comprendre à mon avis et plus facile à étendre au-delà d'un élément.

38voto

RoadieRich Points 303

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 ), 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.

28voto

chepner Points 54078

Il y a des moyens plus efficaces (ce qui ne construit des listes temporaires), mais je pense que c’est la plus concise :

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X