7 votes

Prenez chaque bloc n de la liste

Étant donné une liste :

import string
a = list(string.ascii_lowercase)

Quelle est la façon Pythonique de retourner chaque nième bloc de m éléments ? Notez que cela est différent de simplement retourner chaque nième élément.

Résultat souhaité de prendre chaque 1er des 3 blocs de 3 éléments (prendre 3, sauter 6, prendre 3, sauter 6...) :

['a', 'b', 'c', 'j', 'k', 'l', 's', 't', 'u']

Je peux y arriver comme suit :

import itertools
s1 = a[::9]
s2 = a[1::9]
s3 = a[2::9>    
res = list(itertools.chain.from_iterable(zip(s1,s2, s3)))

Y a-t-il une manière plus propre de le faire ?

3voto

Moses Koledoye Points 60613

Pour une commande fixe de sélection et de saut, vous pouvez envelopper les indices en prenant le modulo sur la longueur totale de la fenêtre (9 ici) et sélectionner uniquement ceux qui se trouvent en dessous du seuil donné, 3:

lst = [x for i, x in enumerate(a) if i % 9 < 3]
print(lst)
# ['a', 'b', 'c', 'j', 'k', 'l', 's', 't', 'u']

Vous pouvez transformer cela en une fonction qui le rend plus intuitif à utiliser:

def select_skip(iterable, select, skip):
    return [x for i, x in enumerate(iterable) if i % (select+skip) < select]  

print(select_skip(a, select=3, skip=6))
# ['a', 'b', 'c', 'j', 'k', 'l', 's', 't', 'u']

2voto

wim Points 35274

Peut-être écrire simplement un générateur est la solution la plus lisible

def thinger(iterable, take=3, skip=6):
    it = iter(iterable)
    try:
        while True:
            for i in range(take):
                yield next(it)
            for i in range(skip):
                next(it)
    except StopIteration:
        return

Cela a l'avantage de fonctionner même si l'entrée est infinie, ou non tranchable (par exemple, des données provenant d'un socket).

2voto

pylang Points 12013

more_itertools est une bibliothèque tierce qui implémente des recettes d'itertools et d'autres outils utiles tels que more_itertools.windowed.

>  pip install more_itertools

Code

import string

from more_itertools import windowed, flatten

m, n = 3, 6
list(flatten(windowed(string.ascii_lowercase, m, step=m+n)))
# ['a', 'b', 'c', 'j', 'k', 'l', 's', 't', 'u']

windowed se déplace naturellement d'une position par itération. En donnant une nouvelle étape en avançant au-delà des chevauchements (m), les fenêtres sont déterminées de manière appropriée.

0voto

Reut Sharabani Points 1353

Vous pouvez le faire en utilisant une recette générique de "morceaux" :

windows = chunks(original_iter, n=3)

Maintenant que vous avez "fenêtré" vos données comme vous le pensez, utilisez la deuxième variante de islice pour ses capacités de 'step' :

# aplatit également la liste en utilisant chain
result = chain.from_iterable(islice(windows, 0, None, 2))

0voto

Mr Geek Points 6389

Vous pouvez utiliser une compréhension de liste et créer une fonction qui le fait pour n'importe quelles valeurs skip, take et list:

import string
import itertools
a = list(string.ascii_lowercase)
def everyNthBlock(a, take, skip):
  res = [a[i:i + take] for i in range(0, len(a) ,skip + take)]
  return list(itertools.chain(*res))

print(everyNthBlock(a, 3, 6))
#^^^^ => ['a', 'b', 'c', 'j', 'k', 'l', 's', 't', 'u']
print(everyNthBlock(a, 4, 7))
#^^^^ => ['a', 'b', 'c', 'd', 'l', 'm', 'n', 'o', 'w', 'x', 'y', 'z']

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