The Networking Event (#4 in The itertools Series • `combinations()` and `permutations()`)
Yteria still can't utter or write the word "for", but she offered to write some code to help organise a networking event
"I'll get the one-to-one meetings sorted", Yteria offered. She was at the one and only meeting of the organising committee for the local Python group. There were five of them sitting around a coffee shop table meant for two people, laptops jostling for table space, balanced precariously at the edge of the table. They'd been a bit disorganised in getting everything sorted, and there was a bit of panic now.
But Yteria couldn't offer to do more. She had picked up quite a bit of work recently, and she had to prioritise her paid gigs. She'll handle setting up the rotas for the one-to-one speed-dating-type networking meetings.
Meeting over. On her way home, she took a slight detour to walk past her local word shop. It had been many months since that unfortunate day when she lost the word "for". Yteria's world is a bit different to yours and mine. Words can be lost or stolen. And when you no longer have a word, you can't speak it, think it, write it, or type it.
She had already enquired at the word shop how much it costs to buy "for". It wasn't cheap. But she had learned to adapt to speaking without using "for". She had also adapted her Python coding style well!
This publication is entirely supported by its readers–there are no adverts, no sponsors! I'd like to continue writing and keep all articles available for free. But it takes a lot of effort and time to get one of these articles out. If you want to support this publication further, you can become a paid subscriber.
You can also support this publication by making a one-off contribution of any amount you wish.
Creating All Possible Pairings Using Nested for
Loops
The list of participants wasn't finalised yet, but Yteria knew she'd have a list of names to work with on the morning of the event. She just needed code that could accept a list of names.
In the networking hour, every participant should meet every other participant for a short one-to-one chat. Yteria's job was to create the rotas. For now, she can just use a list with the organisers' names:

Why don't you have a go at writing a few lines of code to create all possible one-to-one pairings between the people in this list?
Ready?
Here's one possible solution:
This is probably the most straightforward solution. You iterate through the list of participants. Then, for each of the people in the list, you iterate again through the same list of participants. You check you haven't picked the same name twice since there's no point in a person having a one-to-one meeting with themselves, right? And you also check that the pairing is not already included, since Mikey-Yteria and Yteria-Mikey refer to the same one-to-one meeting.
Note the two sets of parentheses when you append the names to the list pairs
, since you append a tuple to pairs
in each iteration.
Let's print out the pairings:
The output shows all possible pairings:
Pairs (using nested `for` loops):
Mikey - Yteria
Mikey - Sam
Mikey - Alex
Mikey - Jordan
Yteria - Sam
Yteria - Alex
Yteria - Jordan
Sam - Alex
Sam - Jordan
Alex - Jordan
Or, if you prefer a different solution, you could try the following:
This time, you use enumerate()
in the outer loop to also access the indices as you iterate through participants
. Then, you only need to loop through part of the list in the inner loop by using the slice index + 1:
. The colon at the end is a shortcut for taking the slice from index + 1
to the end of the list. You can read more about slicing in A Slicing Story. This version gives the same pairings as the previous code.
The Version Without a for
Loop
But Yteria couldn't use either of those versions. Until she finds a way of acquiring the word "for" again, she can't write for
loops.
And the itertools
module has come to the rescue many times for Yteria. This module does what it says on the tin–it provides tools useful for iteration. If you missed other posts in this series, you can find them all here: The `itertools` Series.
Yteria's task was to find all the combinations of two-person groupings. And for those of you familiar with maths terminology, you'll know that combinations is a thing in discrete mathematics. And the itertools
module also has a combinations()
function.
Here's how Yteria used it:
You pass two arguments to itertools.combinations()
:
The list named
participants
with all the people's names. You can use any iterable as an argument.The integer
2
, which represents the size of the groupings you need.
Yteria was looking for groups of two people–pairs–which is why the second argument is 2
.
As you've learnt earlier in The `itertools` Series, the functions in itertools
return iterators. Let's explore this code in an interactive REPL:
The variable name pairs
refers to the iterator returned by combinations()
. That's why you don't see the pairings displayed. But you can cast the iterator to a list:
You can experiment with different integers as the second argument in combinations()
to create groupings of different sizes.
Let's get back to Yteria's script. She still needs to display the groupings, but she still can't use for
loops. Here's a rather clumsy solution to print out the pairings without using a for
loop–but unless you have Yteria's unique problem, don't do this!
Here's the output from this code, confirming you get the same pairings as with the earlier code:
Pairs (using `itertools.combinations()`):
Mikey - Yteria
Mikey - Sam
Mikey - Alex
Mikey - Jordan
Yteria - Sam
Yteria - Alex
Yteria - Jordan
Sam - Alex
Sam - Jordan
Alex - Jordan
This series is about itertools
, and the clumsy code Yteria used to print out the pairings doesn't use any of the itertools
functions. Still, map()
is another tool that can be used for iteration. In the code above, the items in the iterator pairs
are mapped onto the `lambda` function that returns an f-string. The map()
function also returns an iterator. So, you use the unpacking operator *
when you use map()
as an argument in print()
. This is another iteration tool!
Cool. But Is This Solution Better?
Better can be a subjective term. We can debate which is easier to read. The for
loop versions are well-understood by most Python programmers, whatever their level of expertise. The itertools
version is readable only if you know about itertools.combinations()
. But once you know about this function and what it does, the itertools
version becomes more readable. You can understand what the code does instantly without having to work your way through the logic of the nested for
loops.
How about efficiency? The itertools
version ensures that you only create the list, which uses up memory, when you need it, and not earlier, since the itertools
functions return iterators. You could achieve the same effect with for
loops, but it requires a bit more effort.
How about time efficiency? Let's compare the three versions and see how long Python takes to execute these solutions:
You enclose the code for each algorithm in triple-quoted strings, which you then use as arguments in timeit.timeit()
. Here's the output from this code–the usual reminder that the timings will be different on your computer:
Using for loops v1: 0.20314587499888148
Using for loops v2: 0.0652464590020827
Using itertools: 0.03185112500068499
The nested for
loops option, which iterates through each list twice in full, takes the longest. The second for
loop version is more efficient since the code doesn't need to go through each element again in the inner loop.
However, the version using itertools.combinations()
is about twice as fast as the faster of the two for
loop versions. You can try other options, too, such as using list comprehensions, if you prefer. However, the itertools
functions are likely to be quicker than most other solutions since they're optimised for the iteration tasks they're designed for.
But What If The Order of The Pairings Matters?
But what if the order of the groupings matters? What if it matters who's first and who's second? Go and fetch your discrete mathematics textbook again. Or don't bother. Here's what you need. Instead of all the combinations of two people from the list, now you need all the permutations. And itertools
has a permutations()
function:
Each pairing is listed twice in the output since order matters:
Mikey - Yteria
Mikey - Sam
Mikey - Alex
Mikey - Jordan
Yteria - Mikey
Yteria - Sam
Yteria - Alex
Yteria - Jordan
Sam - Mikey
Sam - Yteria
Sam - Alex
Sam - Jordan
Alex - Mikey
Alex - Yteria
Alex - Sam
Alex - Jordan
Jordan - Mikey
Jordan - Yteria
Jordan - Sam
Jordan - Alex
And One More Tool
There's another function to complete the set of combinatorial tools in itertools
. Try using itertools.combinations_with_replacement()
instead of itertools.combinations()
. Do you spot the difference?
Final Words
And there's another task Yteria managed to complete without needing to write a for
loop. The itertools
module came to the rescue, again, with some help from map()
and the unpacking operator *
.
The networking event turned out OK, too…
Code in this article uses Python 3.13
The code images used in this article are created using Snappify. [Affiliate link]
You can also support this publication by making a one-off contribution of any amount you wish.
For more Python resources, you can also visit Real Python—you may even stumble on one of my own articles or courses there!
Also, are you interested in technical writing? You’d like to make your own writing more narrative, more engaging, more memorable? Have a look at Breaking the Rules.
And you can find out more about me at stephengruppetta.com
Further reading related to this article’s topic:
Loss of Words • A Nested Journey (# 1 in The
itertools
Series •product()
)A One-Way Stream of Data • Iterators in Python (Data Structure Categories #6)
The Curious Little Shop at The End of My Street • Python's f-strings
Appendix: Code Blocks
Code Block #1
participants = ["Mikey", "Yteria", "Sam", "Alex", "Jordan"]
Code Block #2
participants = ["Mikey", "Yteria", "Sam", "Alex", "Jordan"]
pairs = []
for first in participants:
for second in participants:
if first != second and (second, first) not in pairs:
pairs.append((first, second))
Code Block #3
# ...
print("Pairs (using nested `for` loops):")
for pair in pairs:
print(f"{pair[0]:6} - {pair[1]}")
Code Block #4
pairs = []
for index, first in enumerate(participants):
for second in participants[index + 1:]:
pairs.append((first, second))
Code Block #5
import itertools
participants = ["Mikey", "Yteria", "Sam", "Alex", "Jordan"]
pairs = itertools.combinations(participants, 2)
Code Block #6
import itertools
participants = ["Mikey", "Yteria", "Sam", "Alex", "Jordan"]
pairs = itertools.combinations(participants, 2)
pairs
# <itertools.combinations object at 0x1039b5490>
Code Block #7
# ...
list(pairs)
# [('Mikey', 'Yteria'), ('Mikey', 'Sam'), ('Mikey', 'Alex'), ('Mikey', 'Jordan'),
# ('Yteria', 'Sam'), ('Yteria', 'Alex'), ('Yteria', 'Jordan'), ('Sam', 'Alex'),
# ('Sam', 'Jordan'), ('Alex', 'Jordan')]
Code Block #8
import itertools
participants = ["Mikey", "Yteria", "Sam", "Alex", "Jordan"]
pairs = itertools.combinations(participants, 2)
print("Pairs (using `itertools.combinations()`):")
print(
*map(lambda pair: f"{pair[0]:6} - {pair[1]}", pairs),
sep="\n",
)
Code Block #9
import itertools
import timeit
participants = ["Mikey", "Yteria", "Sam", "Alex", "Jordan"]
using_for_loops_v1 = """
pairs = []
for first in participants:
for second in participants:
if first != second and (second, first) not in pairs:
pairs.append((first, second))
"""
using_for_loops_v2 = """
pairs = []
for index, first in enumerate(participants):
for second in participants[index + 1:]:
pairs.append((first, second))
"""
using_itertools = "list(itertools.combinations(participants, 2))"
print(
"Using for loops v1:",
timeit.timeit(using_for_loops_v1, globals=globals(), number=100_000),
)
print(
"Using for loops v2:",
timeit.timeit(using_for_loops_v2, globals=globals(), number=100_000),
)
print(
"Using itertools:",
timeit.timeit(using_itertools, globals=globals(), number=100_000),
)
Code Block #10
import itertools
participants = ["Mikey", "Yteria", "Sam", "Alex", "Jordan"]
pairs = itertools.permutations(participants, 2)
print("Pairs (using `itertools.permutations()`):")
print(
*map(lambda pair: f"{pair[0]:6} - {pair[1]}", pairs),
sep="\n",
)
For more Python resources, you can also visit Real Python—you may even stumble on one of my own articles or courses there!
Also, are you interested in technical writing? You’d like to make your own writing more narrative, more engaging, more memorable? Have a look at Breaking the Rules.
And you can find out more about me at stephengruppetta.com