2010-09-23 5 views
1

Étant donné:Cycle de plusieurs itérations?

x = ['a','b','c','d','e'] 
y = ['1','2','3'] 

Je voudrais itérer résultat:

a, 1 
b, 2 
c, 3 
d, 1 
e, 2 
a, 3 
b, 1 

... où cycle, les deux iterables indépendamment jusqu'à ce qu'un nombre donné.

Le cycle de Python (itérable) peut faire ceci w/1 itérable. Les fonctions telles que map et itertools.izip_longest peuvent prendre une fonction pour gérer None, mais ne fournissent pas l'auto-repeat intégré.

Une idée pas si astucieuse est de simplement concaténer chaque liste à une certaine taille à partir de laquelle je peux itérer uniformément. (Boooo!)

Suggestions? Merci d'avance.

Répondre

7
import itertools 
x = ['a','b','c','d','e'] 
y = ['1','2','3'] 
for a, b in itertools.izip(itertools.cycle(x), itertools.cycle(y)): 
    print a, b 
+0

La simplicité gagne! – cwall

10

Le moyen le plus simple de le faire est le suivant: cyclezip1. C'est assez rapide pour la plupart des objectifs.

import itertools 

def cyclezip1(it1, it2, count): 
    pairs = itertools.izip(itertools.cycle(iter1), 
          itertools.cycle(iter2)) 
    return itertools.islice(pairs, 0, count) 

Voici une autre mise en œuvre de ce qui est environ deux fois plus vite quand count est nettement plus grand que le plus petit commun multiple de it1 et it2.

import fractions 

def cyclezip2(co1, co2, count): 
    l1 = len(co1) 
    l2 = len(co2) 
    lcm = l1 * l2/float(fractions.gcd(l1, l2)) 
    pairs = itertools.izip(itertools.cycle(co1), 
          itertools.cycle(co2)) 
    pairs = itertools.islice(pairs, 0, lcm) 
    pairs = itertools.cycle(pairs) 
    return itertools.islice(pairs, 0, count) 

ici, nous profitons du fait que les paires pédalez après la première n d'entre eux où n est le moins Mutliple commun de len(it1) et len(it2). Cela suppose bien entendu que les itérations sont des collections de sorte que demander leur longueur a tout son sens. Une autre optimisation qui peut être fait est de remplacer la ligne

pairs = itertools.islice(pairs, 0, lcm) 

avec

pairs = list(itertools.islice(pairs, 0, lcm)) 

Ceci est loin d'être aussi dramatique d'une amélioration (environ 2% dans mes tests) et loin d'être aussi cohérente . cela nécessite également plus de mémoire. Si it1 et it2 étaient connus à l'avance pour être suffisamment petits pour que la mémoire supplémentaire soit négligeable, alors vous pourriez presser cette performance supplémentaire.

Il est intéressant de noter que la chose évidente à faire dans le cas d'une collection est environ quatre fois plus lente que la première option présentée.

def cyclezip3(co1, co2, count): 
    l1 = len(co1) 
    l2 = len(co2) 
    return ((co1[i%l1], co2[i%l2]) for i in xrange(count)) 
+0

Merci pour l'excellente ventilation! – cwall