By jackhab


2011-03-22 10:01:39 8 Comments

How do I make a for loop or a list comprehension so that every iteration gives me two elements?

l = [1,2,3,4,5,6]

for i,k in ???:
    print str(i), '+', str(k), '=', str(i+k)

Output:

1+2=3
3+4=7
5+6=11

18 comments

@MSeifert 2018-04-09 21:49:22

In case you're interested in the performance, I did a small benchmark (using my library simple_benchmark) to compare the performance of the solutions and I included a function from one of my packages: iteration_utilities.grouper

from iteration_utilities import grouper
import matplotlib as mpl
from simple_benchmark import BenchmarkBuilder

bench = BenchmarkBuilder()

@bench.add_function()
def Johnsyweb(l):
    def pairwise(iterable):
        "s -> (s0, s1), (s2, s3), (s4, s5), ..."
        a = iter(iterable)
        return zip(a, a)

    for x, y in pairwise(l):
        pass

@bench.add_function()
def Margus(data):
    for i, k in zip(data[0::2], data[1::2]):
        pass

@bench.add_function()
def pyanon(l):
    list(zip(l,l[1:]))[::2]

@bench.add_function()
def taskinoor(l):
    for i in range(0, len(l), 2):
        l[i], l[i+1]

@bench.add_function()
def mic_e(it):
    def pairwise(it):
        it = iter(it)
        while True:
            try:
                yield next(it), next(it)
            except StopIteration:
                return

    for a, b in pairwise(it):
        pass

@bench.add_function()
def MSeifert(it):
    for item1, item2 in grouper(it, 2):
        pass

bench.use_random_lists_as_arguments(sizes=[2**i for i in range(1, 20)])
benchmark_result = bench.run()
mpl.rcParams['figure.figsize'] = (8, 10)
benchmark_result.plot_both(relative_to=MSeifert)

enter image description here

So if you want the fastest solution without external dependencies you probably should just use the approach given by Johnysweb (at the time of writing it's the most upvoted and accepted answer).

If you don't mind the additional dependency then the grouper from iteration_utilities will probably be a bit faster.

Additional thoughts

Some of the approaches have some restrictions, that haven't been discussed here.

For example a few solutions only work for sequences (that is lists, strings, etc.), for example Margus/pyanon/taskinoor solutions which uses indexing while other solutions work on any iterable (that is sequences and generators, iterators) like Johnysweb/mic_e/my solutions.

Then Johnysweb also provided a solution that works for other sizes than 2 while the other answers don't (okay, the iteration_utilities.grouper also allows setting the number of elements to "group").

Then there is also the question about what should happen if there is an odd number of elements in the list. Should the remaining item be dismissed? Should the list be padded to make it even sized? Should the remaining item be returned as single? The other answer don't address this point directly, however if I haven't overlooked anything they all follow the approach that the remaining item should be dismissed (except for taskinoors answer - that will actually raise an Exception).

With grouper you can decide what you want to do:

>>> from iteration_utilities import grouper

>>> list(grouper([1, 2, 3], 2))  # as single
[(1, 2), (3,)]

>>> list(grouper([1, 2, 3], 2, truncate=True))  # ignored
[(1, 2)]

>>> list(grouper([1, 2, 3], 2, fillvalue=None))  # padded
[(1, 2), (3, None)]

@mchrgr2000 2019-02-20 10:29:00

A simplistic approach:

[(a[i],a[i+1]) for i in range(0,len(a),2)]

this is useful if your array is a and you want to iterate on it by pairs. To iterate on triplets or more just change the "range" step command, for example:

[(a[i],a[i+1],a[i+2]) for i in range(0,len(a),3)]

(you have to deal with excess values if your array length and the step do not fit)

@Quantum Mechanic 2018-01-19 18:22:07

Use the zip and iter commands together:

I find this solution using iter to be quite elegant:

it = iter(l)
list(zip(it, it))
# [(1, 2), (3, 4), (5, 6)]

Which I found in the Python 3 zip documentation.

it = iter(l)
print(*(f'{u} + {v} = {u+v}' for u, v in zip(it, it)), sep='\n')

# 1 + 2 = 3
# 3 + 4 = 7
# 5 + 6 = 11

To generalise to N elements at a time:

N = 2
list(zip(*([iter(l)] * N)))
# [(1, 2), (3, 4), (5, 6)]

@Vlad Bezden 2018-10-28 17:25:30

Using typing so you can verify data using mypy static analysis tool:

from typing import Iterator, Any, Iterable, TypeVar, Tuple

T_ = TypeVar('T_')
Pairs_Iter = Iterator[Tuple[T_, T_]]

def legs(iterable: Iterator[T_]) -> Pairs_Iter:
    begin = next(iterable)
    for end in iterable:
        yield begin, end
        begin = end

@user391 2018-10-07 02:09:48

a_list = [1,2,3,4,5,6]
empty_list = [] 
for i in range(0,len(a_list),2):
   empty_list.append(a_list[i]+a_list[i+1])   
print(empty_list)

@Ali Katkar 2018-09-24 18:45:04

I need to divide a list by a number and fixed like this.

l = [1,2,3,4,5,6]

def divideByN(data, n):
        return [data[i*n : (i+1)*n] for i in range(len(data)//n)]  

>>> print(divideByN(l,2))
[[1, 2], [3, 4], [5, 6]]

>>> print(divideByN(l,3))
[[1, 2, 3], [4, 5, 6]]

@Scott Ming 2017-08-08 04:12:03

you can use more_itertools package.

import more_itertools

lst = range(1, 7)
for i, j in more_itertools.chunked(lst, 2):
    print(f'{i} + {j} = {i+j}')

@Ofek Ron 2017-05-05 11:46:05

The title of this question is misleading, you seem to be looking for consecutive pairs, but if you want to iterate over the set of all possible pairs than this will work :

for i,v in enumerate(items[:-1]):
        for u in items[i+1:]:

@Chris Malek 2017-02-25 19:16:06

For anyone it might help, here is a solution to a similar problem but with overlapping pairs (instead of mutually exclusive pairs).

From the Python itertools documentation:

from itertools import izip

def pairwise(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
    a, b = tee(iterable)
    next(b, None)
    return izip(a, b)

Or, more generally:

from itertools import izip

def groupwise(iterable, n=2):
    "s -> (s0,s1,...,sn-1), (s1,s2,...,sn), (s2,s3,...,sn+1), ..."
    t = tee(iterable, n)
    for i in range(1, n):
        for j in range(0, i):
            next(t[i], None)
    return izip(*t)

@Sanket Sudake 2016-10-19 11:27:42

Here we can have alt_elem method which can fit in your for loop.

def alt_elem(list, index=2):
    for i, elem in enumerate(list, start=1):
        if not i % index:
           yield tuple(list[i-index:i])


a = range(10)
for index in [2, 3, 4]:
    print("With index: {0}".format(index))
    for i in alt_elem(a, index):
       print(i)

Output:

With index: 2
(0, 1)
(2, 3)
(4, 5)
(6, 7)
(8, 9)
With index: 3
(0, 1, 2)
(3, 4, 5)
(6, 7, 8)
With index: 4
(0, 1, 2, 3)
(4, 5, 6, 7)

Note: Above solution might not be efficient considering operations performed in func.

@Vivek Srinivasan 2016-08-19 12:11:41

Apologies for being late.I hope this will be even more elegant way of doing it.

a = [1,2,3,4,5,6]
zip(a[::2], a[1::2])

[(1, 2), (3, 4), (5, 6)]

@Yuval 2016-02-01 17:58:05

Thought that this is a good place to share my generalization of this for n>2, which is just a sliding window over an iterable:

def sliding_window(iterable, n):
    its = [ itertools.islice(iter, i, None) 
            for i, iter
            in enumerate(itertools.tee(iterable, n)) ]                               

    return itertools.izip(*its)

@Johnsyweb 2011-03-22 10:04:03

You need a pairwise() (or grouped()) implementation.

For Python 2:

from itertools import izip

def pairwise(iterable):
    "s -> (s0, s1), (s2, s3), (s4, s5), ..."
    a = iter(iterable)
    return izip(a, a)

for x, y in pairwise(l):
   print "%d + %d = %d" % (x, y, x + y)

Or, more generally:

from itertools import izip

def grouped(iterable, n):
    "s -> (s0,s1,s2,...sn-1), (sn,sn+1,sn+2,...s2n-1), (s2n,s2n+1,s2n+2,...s3n-1), ..."
    return izip(*[iter(iterable)]*n)

for x, y in grouped(l, 2):
   print "%d + %d = %d" % (x, y, x + y)

In Python 3, you can replace izip with the built-in zip() function, and drop the import.

All credit to martineau for his answer to my question, I have found this to be very efficient as it only iterates once over the list and does not create any unnecessary lists in the process.

N.B: This should not be confused with the pairwise recipe in Python's own itertools documentation, which yields s -> (s0, s1), (s1, s2), (s2, s3), ..., as pointed out by @lazyr in the comments.

@Lauritz V. Thaulow 2011-03-22 10:13:06

Not to be confused with the pairwise function suggested in the itertools recipes section, which yields s -> (s0,s1), (s1,s2), (s2, s3), ...

@Sven Marnach 2011-03-22 10:22:42

It does a different thing. Your version only yields half the number of pairs compared to the itertools recipe function with the same name. Of course yours is faster...

@Lauritz V. Thaulow 2011-03-22 10:24:11

Huh? Your function and the function I referred to do different things, and that was the point of my comment.

@Johnsyweb 2011-03-22 10:30:24

@lazyr, @Sven: Oh, I see. Humble apologies. I should put my glasses on!

@martineau 2012-07-23 17:22:14

@Sven Marnach: I suspect the speed difference is due more to itertools' pairwise() being implemented in terms of tee() than because it returns less data for any given iterable -- of course it's also performing a somewhat different function altogether, so comparing them at all is questionable...

@egafni 2013-01-20 18:48:12

BE CAREFUL! Using these functions puts you at risk of not iterating over the last elements of an iterable. Example: list(grouped([1,2,3],2)) >>> [(1, 2)] .. when you'd expect [(1,2),(3,)]

@Johnsyweb 2013-01-21 02:19:33

@Erik49: In the case specified in the question, it wouldn't make sense to have an 'incomplete' tuple. If you wanted to include an incomplete tuple, you could use izip_longest() instead of izip(). E.g: list(izip_longest(*[iter([1, 2, 3])]*2, fillvalue=0)) --> [(1, 2), (3, 0)]. Hope this helps.

@abarnert 2014-08-03 12:18:59

But to be confused with the grouper recipe in the same documentation. It's definitely worth understanding how this works—that's how you can decide what to do with jagged groups (skip the leftover values, fill with a fillvalue, or return a short group).

@Sailesh Kotha 2018-07-26 04:04:48

@egafni do you how to fix your case?

@Johnsyweb 2018-07-27 00:51:28

@sailesh: You could use izip_longest().

@Sailesh Kotha 2018-07-27 15:24:36

@Johnsyweb Thanks, but my use case is pretty small. So, I'm using current, items = items[:25], items[25:] in a while loop which checks for len(items)

@mic_e 2015-05-24 16:57:24

While all the answers using zip are correct, I find that implementing the functionality yourself leads to more readable code:

def pairwise(it):
    it = iter(it)
    while True:
        yield next(it), next(it)

The it = iter(it) part ensures that it is actually an iterator, not just an iterable. If it already is an iterator, this line is a no-op.

Usage:

for a, b in pairwise([0, 1, 2, 3, 4, 5]):
    print(a + b)

@guilloptero 2015-05-28 08:27:40

This solution allows to generalization to size of tuples > 2

@Drunken Master 2015-07-23 13:59:09

Very elegant and generalization ready solution.

@skyking 2015-09-04 09:32:50

This solution also works if it is only an iterator and not an iterable. The other solutions seem to rely on the possibility to create two independent iterators for the sequence.

@erm3nda 2017-06-22 18:34:00

I found this approach at stackoverflow.com/a/16815056/2480481 before see this answer. Is cleaner, easier than dealing with zip().

@Kentzo 2018-08-13 23:15:37

I like that it allows to avoid tripling memory usage as the accepted answer.

@alexpinho98 2013-05-29 21:03:20

for (i, k) in zip(l[::2], l[1::2]):
    print i, "+", k, "=", i+k

zip(*iterable) returns a tuple with the next element of each iterable.

l[::2] returns the 1st, the 3rd, the 5th, etc. element of the list: the first colon indicates that the slice starts at the beginning because there's no number behind it, the second colon is only needed if you want a 'step in the slice' (in this case 2).

l[1::2] does the same thing but starts in the second element of the lists so it returns the 2nd, the 4th, 6th, etc. element of the original list.

@cababunga 2013-08-09 01:04:58

This answer was already given by Margus two years ago. stackoverflow.com/questions/5389507/…

@Alby 2013-12-26 21:33:06

1 for explaining how [number::number] syntax works. helpful for who doesn't use python often

@pyanon 2011-03-22 16:54:51

>>> l = [1,2,3,4,5,6]

>>> zip(l,l[1:])
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]

>>> zip(l,l[1:])[::2]
[(1, 2), (3, 4), (5, 6)]

>>> [a+b for a,b in zip(l,l[1:])[::2]]
[3, 7, 11]

>>> ["%d + %d = %d" % (a,b,a+b) for a,b in zip(l,l[1:])[::2]]
['1 + 2 = 3', '3 + 4 = 7', '5 + 6 = 11']

@Hamid Rohani 2017-02-06 14:04:33

This is not working on Python-3.6.0 but still working on Python-2.7.10

@vaultah 2017-02-25 14:03:15

@HamidRohani zip returns a zip object in Python 3, which is not subscriptable. It needs to be converted to a sequence (list, tuple, etc.) first, but "not working" is a bit of a stretch.

@Margus 2011-03-22 10:06:12

Well you need tuple of 2 elements, so

data = [1,2,3,4,5,6]
for i,k in zip(data[0::2], data[1::2]):
    print str(i), '+', str(k), '=', str(i+k)

Where:

  • data[0::2] means create subset collection of elements that (index % 2 == 0)
  • zip(x,y) creates a tuple collection from x and y collections same index elements.

@lifebalance 2014-01-26 15:53:17

This can also be extended in case more than two elements are required. For e.g. for i, j, k in zip(data[0::3], data[1::3], data[2::3]):

@kmarsh 2014-05-13 20:19:45

So much cleaner than pulling in an import and defining a function!

@abarnert 2014-08-03 12:20:30

@kmarsh: But this only works on sequences, the function works on any iterable; and this uses O(N) extra space, the function doesn't; on the other hand, this is generally faster. There are good reasons to pick one or the other; being afraid of import is not one of them.

@taskinoor 2011-03-22 10:07:47

A simple solution.

l = [1, 2, 3, 4, 5, 6]

for i in range(0, len(l), 2):
    print str(l[i]), '+', str(l[i + 1]), '=', str(l[i] + l[i + 1])

@Hans de Jong 2014-10-16 22:21:17

what if your list is not even, and you want to just show the last number as it is?

@taskinoor 2014-10-19 06:09:03

@HansdeJong didn't get you. Please explain a little bit more.

@Hans de Jong 2014-10-20 09:39:00

Thanks. I figured already out how to do it. Problem was if you had a list that had not even amount of numbers in it, it would get an index error. Solved it with a try: except:

@Basel Shishani 2015-07-29 11:30:26

Or ((l[i], l[i+1])for i in range(0, len(l), 2)) for a generator, can be easily modified for longer tuples.

Related Questions

Sponsored Content

7 Answered Questions

[SOLVED] How do I get the number of elements in a list?

  • 2009-11-11 00:30:54
  • y2k
  • 3082266 View
  • 1783 Score
  • 7 Answer
  • Tags:   python list

40 Answered Questions

[SOLVED] How to merge two dictionaries in a single expression?

39 Answered Questions

[SOLVED] How to make a flat list out of list of lists

25 Answered Questions

[SOLVED] How do I concatenate two lists in Python?

18 Answered Questions

[SOLVED] How to iterate over rows in a DataFrame in Pandas?

10 Answered Questions

[SOLVED] Iterating over dictionaries using 'for' loops

20 Answered Questions

30 Answered Questions

[SOLVED] How do I check if a list is empty?

  • 2008-09-10 06:20:11
  • Ray Vega
  • 2257068 View
  • 3237 Score
  • 30 Answer
  • Tags:   python list

28 Answered Questions

[SOLVED] Finding the index of an item given a list containing it in Python

  • 2008-10-07 01:39:38
  • Eugene M
  • 3277769 View
  • 2697 Score
  • 28 Answer
  • Tags:   python list indexing

28 Answered Questions

[SOLVED] How to read a file line-by-line into a list?

Sponsored Content