Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Iteration over list slices

I want an algorithm to iterate over list slices. Slices size is set outside the function and can differ.

In my mind it is something like:

for list_of_x_items in fatherList:     foo(list_of_x_items) 

Is there a way to properly define list_of_x_items or some other way of doing this using python 2.5?


edit1: Clarification Both "partitioning" and "sliding window" terms sound applicable to my task, but I am no expert. So I will explain the problem a bit deeper and add to the question:

The fatherList is a multilevel numpy.array I am getting from a file. Function has to find averages of series (user provides the length of series) For averaging I am using the mean() function. Now for question expansion:

edit2: How to modify the function you have provided to store the extra items and use them when the next fatherList is fed to the function?

for example if the list is lenght 10 and size of a chunk is 3, then the 10th member of the list is stored and appended to the beginning of the next list.


Related:

  • What is the most “pythonic” way to iterate over a list in chunks?
like image 282
Rince Avatar asked Aug 26 '09 15:08

Rince


People also ask

How do I loop a range over a list?

To loop through a set of code a specified number of times, we can use the range() function, The range() function returns a sequence of numbers, starting from 0 by default, and increments by 1 (by default), and ends at a specified number.

What is iterating over a list?

Iterator enables you to cycle through a collection, obtaining or removing elements. ListIterator extends Iterator to allow bidirectional traversal of a list and the modification of elements.


2 Answers

If you want to divide a list into slices you can use this trick:

list_of_slices = zip(*(iter(the_list),) * slice_size) 

For example

>>> zip(*(iter(range(10)),) * 3) [(0, 1, 2), (3, 4, 5), (6, 7, 8)] 

If the number of items is not dividable by the slice size and you want to pad the list with None you can do this:

>>> map(None, *(iter(range(10)),) * 3) [(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, None, None)] 

It is a dirty little trick


OK, I'll explain how it works. It'll be tricky to explain but I'll try my best.

First a little background:

In Python you can multiply a list by a number like this:

[1, 2, 3] * 3 -> [1, 2, 3, 1, 2, 3, 1, 2, 3] ([1, 2, 3],) * 3 -> ([1, 2, 3], [1, 2, 3], [1, 2, 3]) 

And an iterator object can be consumed once like this:

>>> l=iter([1, 2, 3]) >>> l.next() 1 >>> l.next() 2 >>> l.next() 3 

The zip function returns a list of tuples, where the i-th tuple contains the i-th element from each of the argument sequences or iterables. For example:

zip([1, 2, 3], [20, 30, 40]) -> [(1, 20), (2, 30), (3, 40)] zip(*[(1, 20), (2, 30), (3, 40)]) -> [[1, 2, 3], [20, 30, 40]] 

The * in front of zip used to unpack arguments. You can find more details here. So

zip(*[(1, 20), (2, 30), (3, 40)]) 

is actually equivalent to

zip((1, 20), (2, 30), (3, 40)) 

but works with a variable number of arguments

Now back to the trick:

list_of_slices = zip(*(iter(the_list),) * slice_size) 

iter(the_list) -> convert the list into an iterator

(iter(the_list),) * N -> will generate an N reference to the_list iterator.

zip(*(iter(the_list),) * N) -> will feed those list of iterators into zip. Which in turn will group them into N sized tuples. But since all N items are in fact references to the same iterator iter(the_list) the result will be repeated calls to next() on the original iterator

I hope that explains it. I advice you to go with an easier to understand solution. I was only tempted to mention this trick because I like it.

like image 172
Nadia Alramli Avatar answered Sep 17 '22 08:09

Nadia Alramli


If you want to be able to consume any iterable you can use these functions:

from itertools import chain, islice  def ichunked(seq, chunksize):     """Yields items from an iterator in iterable chunks."""     it = iter(seq)     while True:         yield chain([it.next()], islice(it, chunksize-1))  def chunked(seq, chunksize):     """Yields items from an iterator in list chunks."""     for chunk in ichunked(seq, chunksize):         yield list(chunk) 
like image 43
Ants Aasma Avatar answered Sep 17 '22 08:09

Ants Aasma