-4

I want to chunk a list in N objects every P objects in list.

For simplicity, lest say I have a list of ints:

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

If I want to take 2 objects every 2 objects, I expect this:

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

Now 2 objects every 3 objects:

[2, 3], [5, 6], [8, 9], [11, 12]

What is the most pythonic way to do it ?

JPFrancoia
  • 4,866
  • 10
  • 43
  • 73
  • A listcomprehension with an "n" I guess. – Anton vBR Jan 22 '18 at 12:36
  • 1
    @Rififi I actually understood your question. I just don't see the effort you put into your task. Did you come up with a somewhat pythonic solution and just want to know if there is a more pythonic one? Then show your attempt. Or do you just want someone to solve your task for you in most pythonic way possible? Then that's what why your question is downvoted. – Tekay37 Jan 22 '18 at 12:59
  • I actually tried, and couldn't solve this at all. I can chunk the list in sub-lists of length N, but I couldn't get the desired output. So I asked, I thought it was a common problem. My attempts weren't brilliant. I don't mind being flagged as a duplicate if it *really* is a duplicate, but people just tend to quickly read a question and say "that seems easy, someone must have answered that before -> downvote" and they didn't understand the question. – JPFrancoia Jan 22 '18 at 13:54
  • The trick is to first chunk it into sub-lists of length P, then reduce each sublist to a length of N. After you made it work, you can refactor your solution to 2 neat list comprehensions (which will be a very pythonic solution) – Tekay37 Jan 22 '18 at 16:15

1 Answers1

1

How about slicing and zipping:

a = [i for i in range(13)]
print('a =',a)

offset = 1
step = 2
b = [(x,y) for x,y in zip(a[offset::step],a[offset+1::step])]
print('b =', b)

offset = 2
step = 3
c = [(x,y) for x,y in zip(a[offset::step],a[offset+1::step])]
print('c =',c)

gives

a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
b = [(1, 2), (3, 4), (5, 6), (7, 8), (9, 10), (11, 12)]
c = [(2, 3), (5, 6), (8, 9), (11, 12)]

EDIT

To generalise the above to arbitrary N and P, you can use slices for list indexing:

def list_segmenter(L, N, P):
    """small function to segment a list (L) into chunks of size N with step size P"""
    slices = [slice(P+i-1,len(L),P) for i in range(N)]
    lists = [L[s] for s in slices]
    return list(zip(*lists))

a = [i for i in range(13)]

##testing:
print(list_segmenter(a,2,2))
print(list_segmenter(a,2,3))
print(list_segmenter(a,4,3))

and the output is:

[(1, 2), (3, 4), (5, 6), (7, 8), (9, 10), (11, 12)]
[(2, 3), (5, 6), (8, 9), (11, 12)]
[(2, 3, 4, 5), (5, 6, 7, 8), (8, 9, 10, 11)]
Thomas Kühn
  • 9,412
  • 3
  • 47
  • 63
  • `list(zip(a[offset::step],a[offset+1::step]))` also is fine here. – RoadRunner Jan 22 '18 at 12:50
  • @RoadRunner True. Do you think there is a huge performance difference? – Thomas Kühn Jan 22 '18 at 12:51
  • @RoadRunner I don't think your answer works for N=2 and P=2. I get ```[(2, 3), (4, 5), (6, 7), (8, 9), (10, 11)]``` instead of ```[(1, 2), (3, 4), (5, 6), (7, 8), (9, 10)]``` – JPFrancoia Jan 22 '18 at 13:55
  • @Rififi which one do you mean, the first or the second? I get exactly the results you post. Are you using the same list as input? – Thomas Kühn Jan 22 '18 at 17:44
  • Your answer works @ThomasKühn (at least the function list_segmenter), I was talking about @RoadRunner comment ```list(zip(a[offset::step],a[offset+1::step]))```, I don't think it works for 2, 2. – JPFrancoia Jan 23 '18 at 08:00