6 votes

Python maintenant, suivant, n itération

Je réfléchis à la meilleure façon d'écrire une fonction où le nombre d'éléments dans chaque tuple peut être défini.

par exemple si c'était

func("bonjour", n=3)

le résultat serait:

('b', 'o', 'n')
('o', 'n', 'j')
('n', 'j', 'o')

Je débute avec l'utilisation de timeit, donc n'hésitez pas à me corriger s'il y a quelque chose de faux ici :

import timeit

def n1(iterable, n=1):
    #now_nxt_deque
    from collections import deque
    deq = deque(maxlen=n)
    for i in iterable:
        deq.append(i)
        if len(deq) == n:
            yield tuple(deq)

def n2(sequence, n=2):
    # now_next
    from itertools import tee
    iterators = tee(iter(sequence), n)
    for i, iterator in enumerate(iterators):
        for j in range(i):
            iterator.__next__()
    return zip(*iterators)

def n3(gen, n=2):
    from itertools import tee, islice
    gens = tee(gen, n)
    gens = list(gens)
    for i, gen in enumerate(gens):
        gens[i] = islice(gens[i], i, None) 
    return zip(*gens)

def prin(func):
    for x in func:
        yield x

string = "Lorem ipsum tellivizzle for sure ghetto, consectetuer adipiscing elit."

print("func 1: %f" %timeit.Timer("prin(n1(string, 5))", "from __main__ import n1, string, prin").timeit(100000))
print("func 2: %f" %timeit.Timer("prin(n2(string, 5))", "from __main__ import n2, string, prin").timeit(100000))
print("func 3: %f" %timeit.Timer("prin(n3(string, 5))", "from __main__ import n3, string, prin").timeit(100000))

résultats:

$  py time_this_function.py 
func 1: 0.163129
func 2: 2.383288
func 3: 1.908363

5voto

Ma proposition serait la suivante,

from collections import deque

def now_nxt_deque(iterable, n=1):
    deq = deque(maxlen=n)
    for i in iterable:
        deq.append(i)
        if len(deq) == n:
            yield tuple(deq)

for i in now_nxt_deque("hello world", 3):
    print(i)

('h', 'e', 'l')
('e', 'l', 'l')
('l', 'l', 'o')
('l', 'o', ' ')
('o', ' ', 'w')
(' ', 'w', 'o')
('w', 'o', 'r')
('o', 'r', 'l')
('r', 'l', 'd')

5voto

Eric Points 36290

Voici une façon vraiment simple de le faire :

  • Clonez votre itérateur n fois en utilisant itertools.tee
  • Faites avancer l'itérateur ième i fois
  • izip les tous ensemble

    import itertools

    def now_next(sequence, n=2): iterators = itertools.tee(iter(sequence), n) for i, iterator in enumerate(iterators): for j in range(i): iterator.next() return itertools.izip(*iterators)

2voto

dav1d Points 2890

Ma solution:

def nn(itr, n):
    iterable = iter(itr)

    last = tuple(next(iterable, None) for _ in xrange(n))
    yield last
    for _ in xrange(len(itr)):
        last = tuple(chain(last[1:], [next(iterable)]))
        yield last

Cela a été fait pour Python 2, si vous voulez l'utiliser avec Python 3, remplacez xrange par range.

next, a un excellent paramètre default, qui sera retourné au lieu de lever une StopIteration, vous pouvez également ajouter ce paramètre par défaut à votre fonction de la manière suivante:

def nn(itr, n, default=None):
    iterable = iter(itr)

    last = tuple(next(iterable, default) for _ in xrange(n))
    yield last
    for _ in xrange(len(itr)):
        last = tuple(chain(last[1:], [next(iterable, default)]))
        yield last

J'ai joué un peu plus avec cela, par exemple en utilisant itr.__class__() comme valeur par défaut, mais cela semble incorrect pour les listes et les tuples, enfin cela semble logique pour les chaînes de caractères.

1voto

1_CR Points 11848

Une variation de la technique d'Eric qui utilise le tranchage

from itertools import tee, islice, izip

def now_next(gen, n=2):
  gens = tee(gen, n)
  gens = list(gens)
  for i, gen in enumerate(gens):
    gens[i] = islice(gens[i], i, None) 
  return izip(*gens)

for x in now_next((1,2,3,4,5,6,7)):
  print x

0voto

Eric Points 36290

Une ligne basée sur la réponse de cravoori :

from itertools import tee, islice, izip

def now_next(gen, n=2):
    return izip(*(islice(g, i, None) for i, g in enumerate(tee(gen, n))))

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