6

Given an input list

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

and group size grp and step step

grp = 3; step = 2

I would like return a list. Note the repetition at the end

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

or if

grp= 4; step = 2

The output should be

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

This is the code I came up with it does not do the cyclic thing. But would like to know if there is a smaller or a simpler solution

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
  • To me the two examples conflict. Please show one for step=1. Or is that what example 1 should be? Commented Dec 18, 2015 at 15:49
  • @Pynchia the two examples don't conflict. Both of them have step=2 so the first number on the second row should be 3 which it is. Commented Dec 18, 2015 at 15:55
  • 3
    Why for grp 4 step 2 do we wrap back around to 1 instead of to 10? Commented Dec 18, 2015 at 15:56
  • OK, it would have been nice to explain what step is (an offset from the beginning of the group, I gather now) Commented Dec 18, 2015 at 16:07
  • on top of @wim comment why is there no fifth row in the second example? Commented Dec 18, 2015 at 16:26

7 Answers 7

3

You can take advantage of the step function in xrange or range depending on what version of python you are using. Then to wrap back around just mod by the length of the list like so

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] 
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks But I also have a follow up question. I actually do this for strings and the output I get is in the form ['0_1_125.jpg', '0_1_126.jpg', '0_1_127.jpg'] ['0_1_126.jpg', '0_1_127.jpg', '0_1_128.jpg'] ['0_1_127.jpg', '0_1_128.jpg', '0_1_129.jpg'] Do you know how I could remove the ' and the [] and commas ??
@ArsenalFanatic to me that looks as if it is a list of lists which you can get rid of the ' [] by printing them rather than printing the list itself.
2
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

Example output:

>>> 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

Comments

2

using a 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)

output:

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]]

You can also join yield the islice object and decide what you want to do with it outside:

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

Output:

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

Or just with modulo:

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)))

3 Comments

@Padraic...I was working for something like your answer but you surpassed me... awesome ... :)
The deque idea is nice.
@PadraicCunningham...Mind Sharing some resources about working with itertools and collections module..as I've been following your answers and I see that you are using a lot of their methods...thanks .. :)
2
[(l+l)[x:x+grp] for x,_ in list(enumerate(l))[::step]]

does the trick in one line

2 Comments

However it should be noted that doing l+l each iteration is amazingly inefficient!
l2 = l+l; [l2[x:x+grp] for x,_ in list(enumerate(l))[::step]] solves the issue
1

The package iteration_utilities1 has a function for this kind of sliding window extraction 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

Applying this to your examples:

>>> 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

The package also includes a convenience class 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

Note that these operations are generator-based so the evaluation is postponed until you iterate over it (for example by creating a list).


Note that I'm the author of iteration_utilities. There are several other packages also providing similar functions, i.e. more-itertools and toolz

Comments

0

Here is yet another solution, which does not use indexes on the list while scanning it. Instead it saves the encountered elements to be repeated and concatenates them with the elements that follow.

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)

produces

[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]

Comments

0

As of version 2.5, more_itertools.windowed supports a step keyword.

> pip install more_itertools

Application:

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]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.