List group items with python step size?

Given an input list

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

and group size grp and step

 grp = 3; step = 2 

I would like to return the 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 exit should be

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

This is the code that I came up with does not do the cyclic thing. But I would like to know if there is a smaller or 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
source share
7 answers

You can use the step function in xrange or range depending on which version of python you are using. Then, to wrap the mod around the length of the list, 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] 
+3
source
 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 

Output Example:

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

using 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 to get 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 a module:

 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
source
 [(l+l)[x:x+grp] for x,_ in list(enumerate(l))[::step]] 

does the trick on one line

+2
source

The iteration_utilities 1 package has a function for unpacking the successive window window in this way:

 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 the ManyIterables convenience 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 

Please note that these operations are based on the generator, so the evaluation is postponed until you go to it (for example, by creating a list ).


Please note that I am the author of iteration_utilities . There are several other packages that also provide similar functions, i.e. more-itertools and toolz

+1
source

Here is another solution that does not use indexes in the list when scanning. Instead, it saves repeating elements that repeat, and combines them with 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] 
0
source

Starting with version 2.5, more_itertools.windowed supports the 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] 
0
source

All Articles