# Get array slices from list of lengths

I have a list of segment lengths and I want to convert it into array slices:

segment_lens = [2, 5, 5]

last_end = 0
start = 0
end = 0

for s_i in range(len(segment_lens)):
start = last_end
end += segment_lens[s_i]
print("Slice: [%s,%s]" %(start, end,))
last_end = end


Here is the intended output, which in my application I would use to slice a list:

Slice: [0,2]
Slice: [2,7]
Slice: [7,12]


Is there a better way to do this? I feel like there should be a python built-in for this, but I'm not sure.

I would probably use iter for this:

def get_chunks(l, chunk_lengths):
it = iter(l)
for chunk_length in chunk_lengths:
yield [next(it) for _ in range(chunk_length)]


Usage:

>>> get_chunks(range(100), [1,2,5])
<generator object get_chunks at 0x7f2744f68910>

>>> list(get_chunks(range(100), [1,2,5]))
[[0], [1, 2], [3, 4, 5, 6, 7]]


Review:

I would make your code at least a function that yeilds the slices and give it a nice name, like I did in the function above.

Note that it is frowned upon in python to iterate over the indices of a list, if all you need are the elements. So prefer this:

for item in l:
print(item)


over

for i in range(len(l)):
print(l[i])


Also note that using "%s" % var style formatting is the old way of doing it. It is recommended to use str.format, which offers a lot more possibilities (none of which you need here, though).

print("Slice: [{},{}]".format(start, end,))


Coming from a focus on numpy, a logical solution is:

In [41]: idx = [0] + [2,5,5]
In [42]: idx = np.cumsum(idx)
In [43]: idx
Out[43]: array([ 0,  2,  7, 12], dtype=int32)
In [44]: slices=[slice(idx[i],idx[i+1]) for i in range(len(idx)-1)]
In [45]: slices
Out[45]: [slice(0, 2, None), slice(2, 7, None), slice(7, 12, None)]


The cumsum could also be implemented with itertools.accumulate:

In [46]: import operator
In [47]: import itertools
In [48]: idx = [0] + [2,5,5]
In [49]: idx = list(itertools.accumulate(idx, operator.add))
In [50]: idx
Out[50]: [0, 2, 7, 12]


Though a generator makes as much sense:

def cumsum(alist):
accum = 0
for i in alist:
yield accum
accum += i
yield accum

In [58]: list(cumsum([2,5,5]))
Out[58]: [0, 2, 7, 12]


An all-in-one generator would be:

def slices(alist):
start, end = 0, 0
for i in alist:
end += i
yield slice(start, end)
start = end

In [65]: list(slices([2,5,5]))
Out[65]: [slice(0, 2, None), slice(2, 7, None), slice(7, 12, None)]


But I prefer the logic of calculating the cumsum first, and the slices from that.