1

Creating a function that takes a list, creates chunks within the list in increasing size starting from 1, and the reverses it. Should be an inplace solution, without having a return statement.

What I have tried:

def backward_chunk(l, size):
start = 0
for end in range(len(l)%size, len(l)+1, size):
    yield l[start:end]
    start = end

Example:

>>> l = [1, 2, 3, 4, 5, 6, 7]
>>> backward_chunk(l, 7)
>>> l
[1, 3, 2, 6, 5, 4, 7]

explained:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] then broken into chunks [(1), (2, 3), (4, 5, 6), (7, 8, 9, 10)] then each chunk is reversed

mod23
  • 11
  • 2

3 Answers3

0

Here is a simple loop to do this. I usually don't recommend modifying a list in place (as it changes it for all the places in the code that thought they had the original version). But since you asked:

def rev_chunks_inplace(a):
    j = 1
    for n in range(2, len(a)):
        i, j = j, j + n
        if i >= len(a):
            break
        a[i:j] = a[i:j][::-1]

Example:

rev_chunks_inplace(a := list(range(14)))
>>> a
[0, 2, 1, 5, 4, 3, 9, 8, 7, 6, 13, 12, 11, 10]

and on your list

l = [1, 2, 3, 4, 5, 6, 7]
rev_chunks_inplace(l)
>>> l
[1, 3, 2, 6, 5, 4, 7]

Note: if you are okay with a generator, it will have no side effect on your list, which usually is preferable (one less opportunity to mess something up that will cause hours of debugging). A similar approach can be used:

def irev_chunks(a):
    j = 0
    for n in range(1, len(a) + 1):
        i, j = j, j + n
        if i >= len(a):
            break
        yield from a[i:j][::-1]
l = [1, 2, 3, 4, 5, 6, 7]
>>> list(irev_chunks(l))
[1, 3, 2, 6, 5, 4, 7]

>>> l
[1, 2, 3, 4, 5, 6, 7]
Pierre D
  • 24,012
  • 7
  • 60
  • 96
0

As others have said, modifying a list in place when passed to a function is generally not a good idea. But since that's what you're looking for:

  1. Start at index 1 (2nd element) since the first one with chunk size 1 doesn't need to be flipped.
  2. Chunk size starts at 2 elements and then increments by 1 for each loop
  3. Each cunk-sized-slice of the list is assigned that slice in reverse using -1 for the step and flipping the start and end indexes (+/- 1)
    • or use the same index but add a [::-1] to reverse it
  4. The starting index of the next chunk is the current start + current chunksize
  5. Repeat until start reaches end of the list*
l = [1, 2, 3, 4, 5, 6, 7]

def flip(lst):
    start = 1
    size = 2  # after the first element, next chunk is size 2
    while start < len(lst):
        lst[start : start + size] = lst[start + size - 1 : start - 1 : -1]
        # or, more readable:
        # lst[start : start + size] = lst[start : start + size][::-1]
        start += size
        size += 1

print(l)
flip(l)
print(l)

Output:

[1, 2, 3, 4, 5, 6, 7]
[1, 3, 2, 6, 5, 4, 7]

If after the last chunk, your list has 2 or more elements left, then it will also flip the last chunk, even if the chunk size is less than what the next one should be. For example:

l = [1, 2, 3, 4, 5, 6, 7, 8, 9]
flip(l)
print(l)
# [1, 3, 2, 6, 5, 4, 9, 8, 7]  (last 2 chunks are both size 3)

* If the last chunk which is less than the required chunk size should not be flipped, change the loop condition to while start + size <= len(lst):, which would give:

l = [1, 2, 3, 4, 5, 6, 7, 8, 9]
flip(l)
print(l)
# [1, 3, 2, 6, 5, 4, 7, 8, 9]  (7 8 9 is not flipped)

# and works normally when the next chunk is the right size:
l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
flip(l)
print(l)
# [1, 3, 2, 6, 5, 4, 10, 9, 8, 7]  (7 8 9 10 is size 4 which is the correct next chunk size)

Edit: And to make it a generator, on the line which does the flipping, instead of assigning it back to the list, put a yield from.

aneroid
  • 12,983
  • 3
  • 36
  • 66
0

You can use itertools.count:

import itertools
def get_chunks(d):
   n, d = itertools.count(1), iter(d)
   while any(k:=[next(d, None) for _ in range(next(n))]):
      yield list(filter(None, k))

l = [1, 2, 3, 4, 5, 6, 7]
result = [i for j in get_chunks(l) for i in j[::-1]]

Output:

[1, 3, 2, 6, 5, 4, 7]
   
Ajax1234
  • 69,937
  • 8
  • 61
  • 102