Учитывая входной список

 l = [1 2 3 4 5 6 7 8 9 10]

И размер группы GRP и шаг шаг

grp = 3; step = 2

Я хотел бы вернуть список. Обратите внимание на повторение в конце

1 2 3
3 4 5
5 6 7
7 8 9
9 10 1

Или если

grp= 4; step = 2

Результат должен быть

1 2 3 4
3 4 5 6
5 6 7 8
7 8 9 10

Этот код, который я придумал, не выполняет циклическую функцию. Но хотелось бы знать, есть ли меньшее или более простое решение

def grouplist(l,grp,step):
    oplist = list()
    for x in range(0,len(l)):
        if (x+grp<len(l)):
        oplist.append(str(l[x:x+grp]))
    return oplist
6
Arsenal Fanatic 18 Дек 2015 в 18:41

7 ответов

Лучший ответ

Вы можете воспользоваться функцией шага в xrange или range в зависимости от того, какую версию python вы используете. Затем обернуть просто мод по длине списка вот так

import sys

def grouplist(l,grp,step):
    newlist=[]
    d = len(l)
    for i in xrange(0,len(l),step):
        for j in xrange(grp):
            newlist.append(l[(i+j)%d])
            sys.stdout.write(str(l[(i+j)%d]) + ' ')
        print

l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print grouplist(l,3,2)
1 2 3 
3 4 5 
5 6 7 
7 8 9 
9 10 1 
[1, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 9, 9, 10, 1]

print grouplist(l,4,2)
1 2 3 4 
3 4 5 6 
5 6 7 8 
7 8 9 10 
9 10 1 2
[1, 2, 3, 4, 3, 4, 5, 6, 5, 6, 7, 8, 7, 8, 9, 10, 9, 10, 1, 2] 
3
SirParselot 18 Дек 2015 в 16:00

Используя deque:

from itertools import islice
from collections import deque



def grps(l, gps, stp):
    d = deque(l)
    for i in range(0, len(l), stp):
        yield list(islice(d, gps))
        d.rotate(-stp)

Выход:

In [7]: l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

In [8]: list(grps(l, 3, 2))
Out[8]: [[1, 2, 3], [3, 4, 5], [5, 6, 7], [7, 8, 9], [9, 10, 1]]

In [9]: list(grps(l, 4, 2))
Out[9]: [[1, 2, 3, 4], [3, 4, 5, 6], [5, 6, 7, 8], [7, 8, 9, 10], [9, 10, 1, 2]]

Вы также можете присоединиться к объекту islice и решить, что вы хотите с ним делать снаружи:

def grps(l, gps, stp):
    d =  deque(l)
    for i in range(0, len(l), stp):
        yield  islice(d, gps)
        d.rotate(-stp)

Выход:

In [11]:     for gp in grps(l, 3,2):
   ....:             print(" ".join(map(str,gp)))
   ....:     
1 2 3
3 4 5
5 6 7
7 8 9
9 10 1

Или просто по модулю

def grps(l, gps, stp):
    ln = len(l)
    for i in range(0, len(l), stp):
        yield (l[j % ln] for j in range(i, i + gps))


for gp in grps(l, 4, 2):
    print(" ".join(map(str, gp)))
2
Padraic Cunningham 18 Дек 2015 в 16:52

Пакет iteration_utilities 1 имеет функцию для такого рода извлечение скользящего окна successive:

from iteration_utilities import successive
from itertools import chain, islice, starmap

def wrapped_and_grouped_with_step(seq, groupsize, step, formatting=False):
    padded = chain(seq, seq[:step-1])
    grouped = successive(padded, groupsize)
    stepped = islice(grouped, None, None, step)
    if formatting:
        inner_formatted = starmap(('{} '*groupsize).strip().format, stepped)
        outer_formatted = '\n'.join(inner_formatted)
        return outer_formatted
    else:
        return stepped

Применяя это к вашим примерам:

>>> list(wrapped_and_grouped_with_step(l, 3, 2))
[(1, 2, 3), (3, 4, 5), (5, 6, 7), (7, 8, 9), (9, 10, 1)]

>>> list(wrapped_and_grouped_with_step(l, 4, 2))
[(1, 2, 3, 4), (3, 4, 5, 6), (5, 6, 7, 8), (7, 8, 9, 10)]

>>> print(wrapped_and_grouped_with_step(l, 3, 2, formatting=True))
1 2 3
3 4 5
5 6 7
7 8 9
9 10 1

>>> print(wrapped_and_grouped_with_step(l, 4, 2, formatting=True))
1 2 3 4
3 4 5 6
5 6 7 8
7 8 9 10

В пакет также входит вспомогательный класс ManyIterables :

>>> from iteration_utilities import ManyIterables
>>> step, groupsize = 2, 4
>>> print(ManyIterables(l, l[:step-1])
...       .chain()
...       .successive(groupsize)
...       [::step]
...       .starmap(('{} '*groupsize).strip().format)
...       .as_string('\n'))
1 2 3 4
3 4 5 6
5 6 7 8
7 8 9 10

Обратите внимание, что эти операции основаны на генераторе, поэтому оценка откладывается до тех пор, пока вы не выполните итерацию (например, путем создания list).


Обратите внимание, что я являюсь автором iteration_utilities. Есть несколько других пакетов, которые также предоставляют аналогичные функции, то есть more-itertools и toolz

1
MSeifert 4 Апр 2017 в 19:40

Вот еще одно решение, которое не использует индексы в списке при сканировании. Вместо этого он сохраняет найденные элементы для повторения и объединяет их с последующими элементами.

def grplst(l, grp, stp):
    ret = []
    saved = []
    curstp = 0
    dx = grp - stp
    for el in l:
        curstp += 1
        if curstp <= stp:
            ret.append(el)
        else:
            saved.append(el)
            if curstp >= grp:
                yield ret+saved
                ret = saved
                saved = []
                curstp = dx
    yield ret+l[:dx]


l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

for g in grplst(l, 3, 2):
    print(g)

for g in grplst(l, 4, 2):
    print(g)

Производит

[1, 2, 3]
[3, 4, 5]
[5, 6, 7]
[7, 8, 9]
[9, 10, 1]

[1, 2, 3, 4]
[3, 4, 5, 6]
[5, 6, 7, 8]
[7, 8, 9, 10]
[9, 10, 1, 2]
0
Pynchia 18 Дек 2015 в 22:11

Начиная с версии 2.5, more_itertools.windowed поддерживает ключевое слово step.

> pip install more_itertools

Заявка:

import itertools as it 

import more_itertools as mit

def grouplist(l, grp, step):
    """Yield a finite number of windows."""
    iterable = it.cycle(l)
    cycled_windows = mit.windowed(iterable, grp, step=step)
    last_idx = grp - 1
    for i, window in enumerate(cycled_windows):
        yield window
        if last_idx >= len(l) - 1:
            break
        last_idx += (i * step)


list(grouplist(l, 3, 2))
# Out: [(1, 2, 3), (3, 4, 5), (5, 6, 7), (7, 8, 9), (9, 10, 1)]

list(grouplist(l, 4, 2))
# Out: [(1, 2, 3, 4), (3, 4, 5, 6), (5, 6, 7, 8), (7, 8, 9, 10)]

list(mit.flatten(grouplist(l, 3, 2))))                  # optional
# Out: [1, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 9, 9, 10, 1]
0
pylang 7 Янв 2017 в 18:46
def grouplist(L, grp, step):
    starts = range(0, len(L), step)
    stops = [x + grp for x in starts]
    groups = [(L*2)[start:stop] for start, stop in zip(starts, stops)]
    return groups

def tabulate(groups):
    print '\n'.join(' '.join(map(str, row)) for row in groups)
    print

Пример вывода:

>>> tabulate(grouplist(range(1,11), 3, 2))
1 2 3
3 4 5
5 6 7
7 8 9
9 10 1

>>> tabulate(grouplist(range(1,11), 4, 2))
1 2 3 4
3 4 5 6
5 6 7 8
7 8 9 10
9 10 1 2
2
wim 18 Дек 2015 в 16:29
[(l+l)[x:x+grp] for x,_ in list(enumerate(l))[::step]]

Делает трюк в одну строку

2
maazza 7 Янв 2017 в 17:28