35 votes

Itérer sur les paires dans une liste (circulaires) en Python

Le problème, c'est facile, je tiens à répéter sur chaque élément de la liste, et la prochaine dans les paires (habillage de la dernière avec la première).

J'ai pensé à deux unpythonic façons de le faire:

def pairs(lst):
    n = len(lst)
    for i in range(n):
        yield lst[i],lst[(i+1)%n]

et:

def pairs(lst):
    return zip(lst,lst[1:]+[lst[0]])

résultat attendu:

>>> for i in pairs(range(10)):
    print i

(0, 1)
(1, 2)
(2, 3)
(3, 4)
(4, 5)
(5, 6)
(6, 7)
(7, 8)
(8, 9)
(9, 0)
>>>

toutes les suggestions sur un plus pythonic façon de faire cela? peut-être il y a une fonction prédéfinie là-bas, je n'ai pas entendu parler?

aussi d'une manière plus générale n fois (avec des triolets, des quatuors, etc. au lieu de paires) version pourrait être intéressant.

27voto

Martin v. Löwis Points 61768
def pairs(lst):
    i = iter(lst)
    first = prev = item = i.next()
    for item in i:
        yield prev, item
        prev = item
    yield item, first

Fonctionne sur n'importe quelle séquence non-vide, pas d'indexation nécessaire.

9voto

fortran Points 26495

J'ai codé moi-même le tuple général versions, j'aime bien la première pour les ellegant simplicité, plus je la regarde, plus Pythonic il me semble... après tout, ce qui est plus Pythonic que d'une doublure avec zip, astérisque argument expansion, interprétations de la liste, liste de tranchage, de liste de concaténation et "range"?

def ntuples(lst, n):
    return zip(*[lst[i:]+lst[:i] for i in range(n)])

Le itertools version devrait être assez efficace, même pour les grandes listes...

from itertools import *
def ntuples(lst, n):
    return izip(*[chain(islice(lst,i,None), islice(lst,None,i)) for i in range(n)])

Et une version pour les non-indexable séquences:

from itertools import *
def ntuples(seq, n):
    iseq = iter(seq)
    curr = head = tuple(islice(iseq, n))
    for x in chain(iseq, head):
        yield curr
        curr = curr[1:] + (x,)

De toute façon, merci à tous pour vos suggestions! :-)

6voto

pillmuncher Points 4726

J'ai, comme toujours, à l'instar de tee shirt:

from itertools import tee, izip, chain

def pairs(iterable):
    a, b = tee(iterable)
    return izip(a, chain(b, [next(b)]))

5voto

hughdbrown Points 15770

Cela peut être satisfaisant:

def pairs(lst):
    for i in range(1, len(lst)):
        yield lst[i-1], lst[i]
    yield lst[-1], lst[0]

>>> a = list(range(5))
>>> for a1, a2 in pairs(a):
...     print a1, a2
...
0 1
1 2
2 3
3 4
4 0

Si vous aimez ce genre de choses, regarder les articles sur python wordaligned.org. L'auteur a un amour spécial des générateurs en python.

2voto

DrBloodmoney Points 1908

J'avais fais comme ça (surtout parce que je peux lire ici):

class Pairs(object):
    def __init__(self, start):
        self.i = start
    def next(self):
        p, p1 = self.i, self.i + 1
        self.i = p1
        return p, p1
    def __iter__(self):
        return self

if __name__ == "__main__":
    x = Pairs(0)
    y = 1
    while y < 20:
        print x.next()
        y += 1

donne:

(0, 1)
(1, 2)
(2, 3)
(3, 4)
(4, 5)
(5, 6)
(6, 7)
(7, 8)
(8, 9)

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