← Python lessons

Python Pairs Without Repeats: Nested Loops and itertools

Part of a free Python course — sign up to save your progress and get AI hints.Sign up free

To list pairs without repeats, start the inner loop just after the outer item, or let itertools.combinations() do it for you.

Read Nested Loops & Ifs and The range() function first.

Start the inner loop after the outer item

A plain nested loop pairs every item with every item, itself included. Loop over positions instead, and start the inner range() at i + 1.

players = ["Ana", "Bo", "Cy"]
for i in range(len(players)):
    for j in range(i + 1, len(players)):
        print(players[i], "vs", players[j])

This prints Ana vs Bo, Ana vs Cy, Bo vs Cy. Each pair appears once, and nobody plays themselves. On the last outer turn, range(3, 3) is empty, so the inner loop does nothing.

Count the pairs

With n items, the outer loop gives n - 1, then n - 2, ... inner turns. That adds up to n * (n - 1) // 2.

players = ["Ana", "Bo", "Cy", "Di"]
count = 0
for i in range(len(players)):
    for j in range(i + 1, len(players)):
        count = count + 1
print(count, len(players) * (len(players) - 1) // 2)

Both numbers are 6. The work grows with the square of the list size: 1,000 items give 499,500 pairs. Nested loops over big lists get slow fast.

Choose combinations, permutations or product

The standard-library itertools module builds these pairs without index arithmetic. Each function takes the items and, for combinations and permutations, how many go in each group.

from itertools import combinations, permutations, product

teams = ["A", "B", "C"]
print(list(combinations(teams, 2)))
print(list(permutations(teams, 2)))
print(list(product(["S", "M"], ["red", "blue"])))

The first line has 3 pairs, the second 6, the third 4.

  • combinations — order doesn't matter, no repeats: ("A", "B") but not ("B", "A"). Use it for "who plays whom".
  • permutations — order matters: home and away games are both listed.
  • product — every item of one list with every item of another, same as a plain nested loop.

The usual mix-up is combinations versus permutations. Ask: is A, B the same result as B, A? If yes, use combinations.

With fewer items than the group size, there are no pairs at all.

from itertools import combinations

print(list(combinations(["A"], 2)))

This prints []. A one-team league has no matches, and no error is raised.

Note: these functions return iterators. Wrap them in list() to see or reuse the pairs; a used-up iterator gives nothing the second time.

See also: Unpacking Values.

Your turn

Print every match in a round robin of teams, one per line as X vs Y, then the number of matches. Use either nested loops or combinations.

teams = ["Ana", "Bo", "Cy", "Di"]
# print each pair once as "X vs Y", then the total number of matches

Expected output

Ana vs Bo
Ana vs Cy
Ana vs Di
Bo vs Cy
Bo vs Di
Cy vs Di
6