String to list of pairs I have an input like this:

x = '415,252,428,233,428,214,394,207,383,205,390,195'


And I want to end up with this

y = [(415,252),(428,233),(428,214),(394,207),(383,205),(390,195)]


The closes I got is

tmp = [int(i) for i in x.split(',')]
y = zip(tmp[::2], tmp[1::2])


How do I get rid of the intermediate list? I need alternative to [::2] that could be used on a generator.
To reduce memory usage you can exploit the mechanics of zip and iter / iterator / generator expression.


Make tmp an iterator.

You can achieve this by changing the brackets from [] to (); changing it from a list comprehension to a generator expression.

You can alternately wrap the list comprehension in an iter call. However that would still be using \$O(n)\$ memory.
In case you don't know what an iterator is, than it's a very useful design pattern.

In short the iterator contains in it some data, and a single method to get the next bit of information. In Python the next function calls this method.

Take the iterator a list provides:

&gt;&gt;&gt; my_data = iter([1, 2, 3, 4])
&gt;&gt;&gt; next(my_data)
1
&gt;&gt;&gt; next(my_data)
2

If you think of zip in terms of iterators, then you'll notice that with two input it works something like:

def zip(a, b):
    while True:
        yield next(a), next(b)


This means if a and b are the same then zip will get the first value and second value in a tuple. Then it will get the third and fourth, until it gets all values.


And so to improve memory usage you can change your code to:

tmp = (int(i) for i in x.split(','))
y = zip(tmp, tmp)


Note: this still runs in \$O(n)\$ space, as x.split() also makes an intermediary list. However it has cut the code from four intermediary lists to just one.



This is a common pattern, as provided in the itertools docs.


  def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --&gt; ABC DEF Gxx"
    args = [iter(iterable)] * n
    return zip_longest(*args, fillvalue=fillvalue)



y = grouper((int(i) for i in x.split(',')), 2)