Juste une petite contribution.
Étant donné que la documentation actuelle de Python ne mentionne pas le mot "window" dans les exemples d'itertool (c.-à-d. au bas de la page d'accueil d'itertool), nous avons décidé de ne pas utiliser le mot "window". http://docs.python.org/library/itertools.html ), voici un extrait basé sur le code de pour grouper qui est l'un des exemples donnés :
import itertools as it
def window(iterable, size):
shiftedStarts = [it.islice(iterable, s, None) for s in xrange(size)]
return it.izip(*shiftedStarts)
En fait, nous créons une série d'itérateurs découpés, chacun ayant un point de départ un point plus loin. Ensuite, nous les regroupons. Notez que cette fonction renvoie un générateur (ce n'est pas directement un générateur lui-même).
Comme pour les versions appending-element et advancing-iterator ci-dessus, les performances (c'est-à-dire ce qui est le mieux) varient avec la taille de la liste et de la fenêtre. J'aime bien cette version parce qu'elle est en deux lignes (elle pourrait être en une ligne, mais je préfère nommer les concepts).
Il s'avère que le code ci-dessus est mauvais . Cela fonctionne si le paramètre passé à itérable est une séquence mais pas si c'est un itérateur. Si c'est un itérateur, le même itérateur est partagé (mais pas en tee) entre les appels islice et cela casse gravement les choses.
Voici un code corrigé :
import itertools as it
def window(iterable, size):
itrs = it.tee(iterable, size)
shiftedStarts = [it.islice(anItr, s, None) for s, anItr in enumerate(itrs)]
return it.izip(*shiftedStarts)
Aussi, une autre version pour les livres. Au lieu de copier un itérateur puis d'avancer les copies plusieurs fois, cette version fait des copies par paire de chaque itérateur au fur et à mesure que nous avançons la position de départ. Ainsi, l'itérateur t fournit à la fois l'itérateur "complet" avec un point de départ à t et aussi la base pour créer l'itérateur t + 1 :
import itertools as it
def window4(iterable, size):
complete_itr, incomplete_itr = it.tee(iterable, 2)
iters = [complete_itr]
for i in xrange(1, size):
incomplete_itr.next()
complete_itr, incomplete_itr = it.tee(incomplete_itr, 2)
iters.append(complete_itr)
return it.izip(*iters)
5 votes
Si vous cherchez à effectuer une sorte d'opération sur chaque fenêtre au fur et à mesure de l'itération (par ex.
sum()
oumax()
), il est utile de garder à l'esprit qu'il existe des algorithmes efficaces pour calculer la nouvelle valeur pour chaque fenêtre dans constant temps (indépendamment de la taille de la fenêtre). J'ai rassemblé certains de ces algorithmes dans une bibliothèque Python : en roulant .