On Shared Birthdays (and a Bit on Pythagorean Triplets) • Pythonic Code
A Python journey through probabilities, `itertools`, and some more Pythonic tools–and yes, we'll explore the Birthday Paradox
You know what they say about buses. You wait for ages, and then two arrive at once. Or is it three? In any case, I had a similar experience with a specific Python tool over a two-day period last week.
It all started with my son writing Python code to find all the Pythagorean integer triplets between 1 and 1,000. But this sounds nerdy, even for a Python publication. So, I'll leave it until later.
Instead, let me start with the well-known Birthday Paradox, inspired by this week's edition of one of my favourite newsletters, Today You Should Know. I'll explore a few different Python-based solutions to confirm and, more importantly, convince you that its result is valid despite all your protestations!
Twenty-Three People Walk Into a Bar
This is no joke. If you're familiar with the Birthday Paradox, you know what's coming. I'll run this as a virtual experiment.
Twenty-three people walk into a bar:

It was a small bar, and it had been a quiet day. The bar owner was thinking of closing early. But not now. This group of 23 seemed ready to party. He thought he should make the first move.
"Hello, dear friends!" he said with a cheery voice he'd practised for decades, "and welcome." And now for his hook: "Here's what we'll do–If any two of you happen to share the same birthday, the first round is on me!"
That made him look generous, but what are the chances of two of them sharing a birthday, he thought? He was safe. He could already see the cash flowing into his battered cash register.
This is a virtual story. So, let's simulate their birthdays. You could simply use random numbers between 1 and 365–let's ignore leap years for this exercise. But let's make it more realistic and generate random dates.
In 2024 I recorded an extensive curriculum of video courses covering beginner and intermediate level Python for The Python Coding Place.
The Place wants to make these as accessible as possible and now provides membership for either $15 / month or through a one-time payment of $200. You get access to all the courses and to the members' forum. Make the most of this offer while it lasts.
This is a sponsored message.
Generating Random Birthdays
You'll use the datetime
module and the proleptic Gregorian ordinal–yes, I had to Google that, too. In brief, this technique represents each day as an integer, starting from 1 for the 1st of January of the year 1:
Therefore, the 1st of January of the year 2 is 366, and the 1st of January of this year, 2025, is 739,252:
So, we can use this in reverse and create random integers representing a whole year–let's use 2025–and then convert them to a month and day:
The values start
and end
are integers representing the first and last day of 2025. You choose a random integer between these numbers, and .fromordinal()
converts each of these integers to a datetime.datetime
object. Remember that random.randint()
, unlike many other Python functions with number ranges, includes the endpoint, too.
You use a list comprehension to create a list of 23 random birthdays.
If you include the random.seed(1)
call, you'll always get the same values–this is useful for testing your code as you add more to it. Otherwise, you'll get a fresh selection of random birthdays each time you run the code. Here's the output:
[
datetime.datetime(2025, 3, 10, 0, 0),
datetime.datetime(2025, 10, 19, 0, 0),
datetime.datetime(2025, 2, 2, 0, 0),
datetime.datetime(2025, 5, 11, 0, 0),
...,
datetime.datetime(2025, 10, 30, 0, 0),
]
So, there's the 10th of March, the 19th of October, the 2nd of February, and so on. I truncated the output above and displayed it in a friendlier manner than the one your code shows.
Now, help the bar owner go through the birthdays and count how often each one occurs in the group of 23:
The Counter
class from the collections
module creates a mapping that contains all the datetime.datetime
objects as keys. The value of each key is the number of times it occurs in the original iterable, which is birthdays
in this example:
Counter({
datetime.datetime(2025, 3, 10, 0, 0): 1,
datetime.datetime(2025, 10, 19, 0, 0): 1,
datetime.datetime(2025, 2, 2, 0, 0): 1,
datetime.datetime(2025, 5, 11, 0, 0): 1,
...,
datetime.datetime(2025, 10, 30, 0, 0): 1
})
Scroll through all the birthdays, and you'll see a 1 next to each one of them. They all appear only once. You can also confirm this by finding the single most common birthday:
And if there's more than one item with the same most common value, this method shows the first one:
[(datetime.datetime(2025, 3, 10, 0, 0), 1)]
The output is a list since you can choose to show the two or three or any number of the most common values. But in this case, you just want to know the most common one, and if its value is 1, as it is in this case, it means that no one shares a birthday.
The bar owner was pleased. No free drinks, as he had expected, and 23 people willing to spend their own money!
Before they left, one of the group approached the bar owner: "This is a nice little bar. It's exactly what I was looking for for the end-of-course celebration. I'll have a new batch of students next week, and I'll bring them here again. See you then!"
The Next Week • Twenty-Three New People Walk Into the Bar
As promised, the course organiser brought his new group of students the following week. He was the only one who'd been there the previous week.
"Same deal as last week, my friend", said the bar owner, "first round for everyone on me if any two of you share a birthday!" He was licking his lips–figuratively, not literally–ready for the cash bonanza!
Let's run the code again. However, recall you fixed the randomness by using random.seed(1)
. You shouldn't keep the same seed number since this new group of 23 won't have the same birthdays as the first group. For simplicity, let's ignore the fact that the group leader is the same person and, therefore, has the same birthday as the one he had the previous week!
Use a seed of 2 instead:
I'll just show the final printout below, the one showing the most common birthday:
[(datetime.datetime(2025, 11, 7, 0, 0), 2)]
Oh no!
Two people do share the same birthday–the 7th of November. What rotten luck! The bar owner had to give everyone a free drink. Luckily for him, they stayed a while and ordered more drinks later.
Was the bar owner that unlucky?
The Birthday Paradox
You may already be familiar with the Birthday Paradox. But not everyone is. The bar owner certainly wasn't. The counterintuitive result–which is why it's called a "paradox"–states that you only need 23 people to have a 50% chance that at least two people share the same birthday.
You think it doesn't sound right? Let's test it. You can fast-forward the next twenty weeks at the bar, with a new group of 23 people walking in each week. You can delete the random.seed()
line now and let randomness do its thing:
Let's go through the key steps in this code:
You include a
repeats
variable name to determine how often you want to repeat this virtual experiment. Each repeat is equivalent to a new week in the bar when a fresh group of 23 walks in.You add a
for
loop to repeat this experiment. Before the loop, you setcount
to 0. This variable name stores the number of times at least two people share the same birthday.The code in the loop is similar to your earlier version.
You create a list of 23 randomly chosen birthdays each time.
If the most common birthday has a value of 2 or more, then some people share a birthday. You add 1 to
count
.The last line in the
for
loop uses Python's conditional expression (sometimes rather loosely referred to as the ternary operator) as the right-hand side operand for the+=
operator. This conditional expression evaluates to 1 if the most common birthday occurs two or more times and to 0 if it only occurs once.Recall that
most_common
contains the return value from the call toCounter.most_common()
, which returns a list of tuples. In this case, the list contains only one tuple since you use the argument 1 when you call.most_common()
.
Therefore,most_common[0][1]
fetches the first and only value in the listmost_common
and then the second element from that tuple, which is the number of occurrences.
The f-string uses the
:.1%
format specifier, which displays the number as a percentage with one digit after the decimal point.
Here's the output from this code–note that as there's no seed set, the values you get will change each time you run your code and won't necessarily be similar to the one shown here:
The percentage of groups of 23 where at
least 2 people share a birthday is 55.0%
However, to get a more meaningful estimate of what you should expect on average, you can run this experiment for a much larger value of repeats
:
You can still expect some variation in the outputs each time you run this, but your values will be much closer to 50% now:
The percentage of groups of 23 where at
least 2 people share a birthday is 50.4%
You can try larger values for repeats
if you have time to spare!
It's true, then. All you need is 23 people to have just over a 50% chance that two of them share a birthday. We'll explore the logic behind this with some more Python code later.
What if you have, say, 50 people? Change n_people
to 50, and you'll get:
The percentage of groups of 50 where at
least 2 people share a birthday is 97.0%
It's not quite a certainty–it never is–but 97% is high enough.
The Python Coding Stack is free. All articles are free forever. But if you enjoy these articles and find them useful, and if you’re in a position to do so, you can become a paid subscriber to help support this publication.
You can also make a one-off contribution of any amount you wish.
The Three-Shared-Birthday Variant
This virtual experiment allows you to test your statistical intuitions further. The birthday paradox is always stated as the number of people you need to have a 50% chance that two people share the same birthday.
How many people do you think you need for a 50% chance of three people sharing a birthday?
Don't cheat! Come up with a number based on your intuition before reading on…
You can now modify the code, starting again with 23 people:
You add the new variable name n_shared_bdays
and set it to 3. You then use this variable name in the conditional expression to increment count
, and in the f-string, you use it to display the result.
Since you still have 23 people in this code, the likelihood that three share a birthday is very small:
The percentage of groups of 23 where at
least 3 people share a birthday is 1.2%
I'll let you explore different values for n_people
to find out the "magic" number, which is, of course, not magic at all! It's probability theory! You can also experiment with different values of n_shared_bdays
now.
A Different Approach
In the previous section, you ran a virtual experiment by creating a group of people with random birthdays and finding out how many share a birthday. By running this experiment a large number of times, you get a reasonable approximation of the probability.
But there are alternative ways of reasoning that should lead you to the same result without the brute force techniques. This is a Python publication, not a statistics one, so I'll take the route that explores some interesting Python tools in this section.
The Birthday Paradox Logic
Let's go back to the classic Birthday Paradox that looks for the probability that at least two people out of a group of 23 share the same birthday. I’ll use one of the common approximations to solve this paradox. (And see the appendix for the exact solution.)
You can find all possible pairs of people in the group. Then you work out the probability that the second person in each pair doesn't have the same birthday as the first person in the pair. Finally, you extend this probability for all the pairs. Let's try this.
Let's take one such pair. Let's say Matthew and Jason. Matthew's birthday could be any of the 365 days of the year. It doesn't matter which one–let's say it's the 3rd of June. The likelihood that Jason doesn't share a birthday with Matthew is 364 / 365 since if Jason's birthday is on any of the rest of the 364 days of the year, then he doesn't share his birthday with Matthew.
And 364 / 365 is 0.99726027 or 99.73%. Take any two people, and it's very unlikely they will share a birthday. That, at least, matches our intuitions!
Now, take a second pair of people in the group of 23. This could be any two of the remaining people in the group. Or it could also include Matthew or Jason, but not both since you've already dealt with the Matthew-Jason pairing. Let's say that this is the Mary-David pairing. The probability these two don't share a birthday is the same as for the Matthew-Jason pairing since the logic doesn't change–99.73%
But now you can work out the likelihood that Matthew doesn't share a birthday with Jason and also that Mary doesn't share a birthday with David. This is 0.99726027 * 0.99726027, which is 0.99452805 or 99.45%. Still high but lower than the probability when considering only one pair. It's now a bit more likely that one of the two pairings has a shared birthday.
Add a third pair, and the probability no pairing shares a birthday is 0.99726027 * 0.99726027 * 0.99726027 or 0.99726027 ^ 3, which is 0.99180331 or 99.18%.
Add more pairs, and the probability that there are no shared birthdays within pairs gets lower.
So, we just need to raise 0.99726027 to the power of the total number of pairs we can possibly have in a group of 23. Recall that 0.99726027 is 364 / 365, which is the probability that the second person in a pair doesn't share their birthday with the first.
But how many pairs do we have?
A Semi-Brute Force Solution
How many possible pairs can we have in a group of 23 people? This question is easy or hard, depending on how much discrete mathematics and probability theory you studied in the past.
Let's use the lazy approach first:
You loop through the 23 people in the first loop and then again in the second loop. This creates pairings between people as long as you exclude those iterations when both loops refer to the same person–you can't have a person form a pair with himself or herself!
However, you also need to divide the final count by two since the nested loops count each pair twice. For example, it would count the Matthew-Jason pair and the Jason-Matthew pair, but these are the same pairing.
Note that the code above simply uses numbers from 0 to 22 rather than names, but it doesn't matter.
You could also replace the call to range()
in the second loop with range(first, n_people)
. Then you don't need to divide the total count by two since the second loop already excludes the numbers (people) included in the first loop. You'll see this technique in use later on.
Run the code. It gives us 253 possible pairs.
Therefore, the probability that none of these 253 pairs has two people with the same birthday is 0.99726027 ^ 253, which is 0.49952234. This is the probability that no two people share a birthday in the group of 23.
When dealing with probabilities, 1 represents all possible scenarios (that's 100%). Therefore, the probability that at least one of the pairs includes two people with the same birthday is 1-0.49952234, which is 0.50047766 or 50.05%.
And that's your Birthday Paradox proved.
The code you used to find how many possible pairs there are works fine. But you can improve on it. Let's look at some alternatives.
A More Pythonic Semi-Brute Force Solution
There's a more Pythonic way to deal with such a nested loop scenario.
First, let's explore itertools.product()
in a simple example:
The callable product()
returns an iterator, which is why you cast it to a list to display the values. It pairs the elements of the two iterables in all possible ways. This is equivalent to using a nested loop such as the following:
And if you wish to use the same iterable in both inner and outer loops, then you can replicate this behaviour with:
A minor sidenote: I described product()
as a callable rather than a function earlier in this section. It looks like a function, and you use it like a function, but technically, it's a class. However, in Python, duck typing rules! Therefore, what matters is what you can do with an object and not what it is. You can call a function and you can also call a class. They're both callables. But it's fine if you want to call product()
a function–no one will be upset!
There are two issues with using product()
for our present task, which is finding the number of possible pairs in a group of 23 people. The pairings created by product()
include:
Pairs where a value is paired with itself, such as
(2, 2)
Symmetric pairs, such as
(2, 4)
and(4, 2)
You don't want pairs that fall in either of these categories in your final count. In the first brute force attempt earlier, you dealt with the first issue with the if
statement in the for
loop, if first != second
, and you accounted for the second issue by dividing by two.
The itertools
module comes to the rescue with another function: itertools.combinations()
:
Note that the repeat
parameter in itertools.product()
represents an optional argument, and it's also a keyword-only argument–you must use repeat=2
to pass this optional argument to product()
. However, the equivalent parameter in itertools.combinations()
represents a required argument and can be passed as a positional argument. The parameter name in combinations()
is just r
instead of repeat
, just in case you choose to use it as a named or keyword argument.
The combinations()
callable–also technically a class but that you use like a function–finds all possible combinations for pairings but doesn't include pairing an item with itself, and it doesn't repeat each pairing by changing the order. Note that there's no (6, 2)
, for example, since that's the same pairing as (2, 6)
.
Therefore, you can find the total number of pairings in a group of 23 people using combinations()
, which also returns an iterator:
And this gives you 253 pairs, the same result you obtained earlier when you used the nested for
loops.
An Analytical Solution
There are more ways to figure out how many possible pairs there are in a group of 23 people. Here's one that's more rigorous than the counting methods above.
There are 23 options for choosing the first person you want to put in a pair. For each one of those 23 options, you're left with 22 options for the second person in the pair since the first person in the pair can't be chosen to fill the second place in that pairing.
And 23 * 22 is 506. There are 506 ways of pairing 23 people. But this includes each pair twice. You're picking the Matthew-Jason and the Jason-Matthew pair. So, you need to divide by 2, which gets you back to 253. This is the combinations formula that's formally written as 23! / (21! * 2!), but I'll leave this for more maths-y publications.
What matters is that whatever route you choose, you'll end up with 253 possible pairs in a group of 23 people. And that's what you need to work out the Birthday Paradox probability. As you saw earlier, the probability that a pair doesn't share a birthday is 364 / 365, and you need to raise this to the power of the number of all the pairings, which you've now established to be 253 using several methods.
Pythagorean Triplets
I mentioned how I ended up using the same tool several times within a couple of days. It all started when my son asked for help with some Python code he was working on. He wanted to find all the Pythagorean integer triplets between 1 and 1,000–all the sets of three integers that satisfy Pythagoras's theorem.
His code was similar to this version, but I placed it in a function and tidied up a few things:
The code within the function has nested for
loops to get all possible pairs of numbers within the required range. The code then checks whether the hypothenuse you obtain from that pair of numbers using Pythagoras's theorem is itself an integer. If it is, the code in the loop adds a tuple with all three numbers to the list triplets
.
Here's the output for find_pythagorean_triplets(1, 15)
:
[(3, 4, 5), (4, 3, 5), (5, 12, 13), (6, 8, 10),
(8, 6, 10), (8, 15, 17), (9, 12, 15), (12, 5, 13),
(12, 9, 15), (15, 8, 17)]
This is good–all the triplets shown are Pythagorean triplets. The sum of the squares of the first two is equal to the square of the third one.
However, there are repetitions. For example, the first two tuples show the same triplet: (3, 4, 5)
and (4, 3, 5)
.
You could sort the triplets in ascending order and then cast the triplets
list into a set to eliminate repeated entries. However, a simpler option is to begin the range of the inner loop from a
instead of start
to avoid looping through the values already covered by previous iterations of the outer loop:
The output now shows the correct Pythagorean triplets with no repetitions:
[(3, 4, 5), (5, 12, 13), (6, 8, 10),
(8, 15, 17), (9, 12, 15)]
Using itertools
But you've seen this already. The itertools
module offers a more Pythonic way to replace these nested for
loops.
This is similar to the Birthday Paradox problem. So, let's define another function:
In this version, there's only one for
loop, but it loops through the iterator created by itertools.combinations()
. This itertools
callable, as you saw earlier, finds all the combinations of pairs from the range of numbers provided.
This gives the following output:
[(3, 4, 5), (5, 12, 13), (6, 8, 10),
(8, 15, 17), (9, 12, 15)]
And that's the same output as the previous version of the code.
However, there's another important but, in this case, insignificant point. Look back at the code from earlier when exploring itertools.combinations()
:
Note how each number is not paired with itself. This was an essential condition for the Birthday Paradox since a person couldn't be paired with himself or herself.
But there are times when you want to allow pairs made up of the same elements. In these cases, you can use a different callable called combinations_with_replacement()
:
Note that the output now also includes (2, 2)
, (4, 4)
, and so on.
There's no reason to exclude these pairs when working out Pythagorean triplets–in theory. So, you could use this function in find_pythagorean_triplets_itertools()
.
However, as it turns out, this won't make a difference to the results. There are no Pythagorean triplets of integers where two of the sides are equal. You can actually prove this, but that's again too maths-y and not relevant for this article.
You can confirm that the two functions–the one using nested for
loops and the one using itertools.combinations()
–give the same output:
This code outputs True
.
Incidentally, if you have an application where the order of the items in each pair matters, you can use itertools.permutations()
instead of combinations()
.
Is itertools.combinations()
Faster?
Why use itertools.combinations()
rather than the nested for
loops option? Is it faster? Let's find out:
The timeit.timeit()
function runs the function 100 times since number=100
. Here's the output:
Timing 'find_pythagorean_triplets()':
6.1081562919935095
Timing 'find_pythagorean_triplets_itertools()':
6.1617513750024955
Right, there isn't much difference between the two in terms of performance. Remember that your mileage may vary depending on your setup and the operations your operating system is running in the background.
The Python version you're using will also make a difference. For example, this same code on the same computer took about 25 seconds for each function instead of 6 seconds when using Python 3.9 instead of 3.13.
However, many Python programmers will find the version with itertools.combinations()
more readable and less prone to bugs. Compare the nested for
loops and the version using combinations()
and see what you think.
And since combinations()
returns an iterator, you're also more likely to keep your memory footprint low in general.
Final Words
Most of today's article focused on convincing you the Birthday Paradox is real, even if it's counterintuitive! But exploring the Birthday Paradox took us through a journey across several Python goodies, including product()
and combinations()
from the itertools
module and Counter()
from the collections
module.
These tools, and indeed other tools in both the itertools
and collections
modules, are part of Python's 'Swiss army knife' tools that enable you to write more Pythonic code. You can get by without these modules, but you'd be losing out!
Now, let's hope the bar owner reads this article.
Appendix: The Exact Birthday Paradox Solution
The approximation I used in the main article gives very accurate results, but it’s still an approximation.
The exact solution goes as follows. We want to ensure no person shares a birthday with anyone else.
Pick any of the 23 people. They can have any birthday. It doesn’t matter. This has a probability of 1, or 365 / 365—any of the 365 days available is fine!
But the second person you pick must have one of the remaining 364 days as their birthday. That’s a probability of 364 / 365. So, the total probability for the first two people to not share a birthday is:
(365 / 365) * (364 / 365)
The third person must have their birthday on any of the remaining 363 days since two days are already “taken”. Therefore, the probability that three people don’t share a birthday is:
(365 / 365) * (364 / 365) * (363 / 365)
Keep going until you reach the 23rd person. By this point, there are only 343 days of the year left, since the remaining 22 have already been used by the first 22 people.
Therefore, the overall probability that none of the 23 people share a birthday is:
(365 / 365) * (364 / 365) * (363 / 365) * … * (343 / 365)
or
365! / ( (365 - 23)! * (365 ^ 23) )
import math
n_people = 23
p_ = math.factorial(365) / (math.factorial(365 - n_people) * 365 ** n_people)
p = 1 - p_
print(f"The probability that at least two people share a birthday "
f"in a group of {n_people} is {p:.1%}")
The output is:
The probability that at least two people share a birthday in a group of 23 is 50.7%
Credit to Rodrigo Girão Serrão for convincing me to also add this exact solution!
Code in this article uses Python 3.13
The code images used in this article are created using Snappify. [Affiliate link]
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:
When a Duck Calls Out • On Duck Typing and Callables in Python
Duck Typing in Python: Writing Flexible and Decoupled Code – Real Python
If You Find if..else in List Comprehensions Confusing, Read This, Else…
Appendix: Code Blocks
Code Block #1
n_people = 23
Code Block #2
import datetime
datetime.datetime(1, 1, 1).toordinal()
# 1
Code Block #3
datetime.datetime(2, 1, 1).toordinal()
# 366
datetime.datetime(2025, 1, 1).toordinal()
# 739252
Code Block #4
import datetime
import random
n_people = 23
random.seed(1)
year_start = datetime.datetime(2025, 1, 1)
start = year_start.toordinal()
end = start + 364
birthdays = [
datetime.datetime.fromordinal(
random.randint(start, end)
)
for _ in range(n_people)
]
print(birthdays)
Code Block #5
import collections
# ...
grouped_birthdays = collections.Counter(birthdays)
print(grouped_birthdays)
Code Block #6
# ...
print(grouped_birthdays.most_common(1))
Code Block #7
# ...
random.seed(2)
# ...
Code Block #8
import collections
import datetime
import random
n_people = 23
repeats = 20
# random.seed(2)
year_start = datetime.datetime(2025, 1, 1)
start = year_start.toordinal()
end = start + 364
count = 0
for _ in range(repeats):
birthdays = [
datetime.datetime.fromordinal(
random.randint(start, end)
)
for _ in range(n_people)
]
most_common = collections.Counter(birthdays).most_common(1)
count += 1 if most_common[0][1] >= 2 else 0
print(f"The percentage of groups of {n_people} "
f"where at least 2 people share a birthday "
f"is {count/repeats:.1%}")
Code Block #9
# ...
repeats = 100_000
# ...
Code Block #10
import collections
import datetime
import random
n_people = 23
repeats = 100_000
n_shared_bdays = 3
# random.seed(2)
year_start = datetime.datetime(2025, 1, 1)
start = year_start.toordinal()
end = start + 364
count = 0
for _ in range(repeats):
birthdays = [
datetime.datetime.fromordinal(
random.randint(start, end)
)
for _ in range(n_people)
]
most_common = collections.Counter(birthdays).most_common(1)
count += 1 if most_common[0][1] >= n_shared_bdays else 0
print(f"The percentage of groups of {n_people} "
f"where at least {n_shared_bdays} people share a birthday "
f"is {count/repeats:.1%}")
Code Block #11
n_people = 23
count = 0
for first in range(n_people):
for second in range(n_people):
if first != second:
count += 1
print(count / 2)
Code Block #12
import itertools
list(itertools.product([2, 4, 6, 8], [10, 20, 30, 40]))
# [(2, 10), (2, 20), (2, 30), (2, 40), (4, 10), (4, 20),
# (4, 30), (4, 40), (6, 10), (6, 20), (6, 30), (6, 40),
# (8, 10), (8, 20), (8, 30), (8, 40)]
Code Block #13
for a in [2, 4, 6, 8]:
for b in [10, 20, 30, 40]:
...
Code Block #14
list(itertools.product([2, 4, 6, 8], repeat=2))
# [(2, 2), (2, 4), (2, 6), (2, 8), (4, 2), (4, 4),
# (4, 6), (4, 8), (6, 2), (6, 4), (6, 6), (6, 8),
# (8, 2), (8, 4), (8, 6), (8, 8)]
Code Block #15
list(itertools.combinations([2, 4, 6, 8], 2))
# [(2, 4), (2, 6), (2, 8), (4, 6), (4, 8), (6, 8)]
Code Block #16
import itertools
n_people = 23
print(
len(
list(itertools.combinations(range(n_people), 2))
)
)
Code Block #17
import math
def find_pythagorean_triplets(start=1, stop=1000):
triplets = []
for a in range(start, stop + 1):
for b in range(start, stop + 1):
c = math.sqrt(a ** 2 + b ** 2)
if c == int(c):
triplets.append((a, b, int(c)))
return triplets
print(
find_pythagorean_triplets(1, 15)
)
Code Block #18
import math
def find_pythagorean_triplets(start=1, stop=1000):
triplets = []
for a in range(start, stop + 1):
for b in range(a, stop + 1):
c = math.sqrt(a ** 2 + b ** 2)
if c == int(c):
triplets.append((a, b, int(c)))
return triplets
print(
find_pythagorean_triplets(1, 15)
)
Code Block #19
import itertools
import math
def find_pythagorean_triplets(start=1, stop=1000):
# ...
def find_pythagorean_triplets_itertools(start=1, stop=1000):
triplets = []
for a, b in itertools.combinations(
range(start, stop + 1),
2,
):
c = math.sqrt(a ** 2 + b ** 2)
if c == int(c):
triplets.append((a, b, int(c)))
return triplets
print(
find_pythagorean_triplets_itertools(1, 15)
)
Code Block #20
import itertools
list(itertools.combinations([2, 4, 6, 8], 2))
# [(2, 4), (2, 6), (2, 8), (4, 6), (4, 8), (6, 8)]
Code Block #21
list(
itertools.combinations_with_replacement(
[2, 4, 6, 8],
2,
)
)
# [(2, 2), (2, 4), (2, 6), (2, 8), (4, 4), (4, 6),
# (4, 8), (6, 6), (6, 8), (8, 8)]
Code Block #22
# ...
print(
find_pythagorean_triplets()
== find_pythagorean_triplets_itertools()
)
Code Block #23
import itertools
import math
import timeit
# ...
print(
"Timing 'find_pythagorean_triplets()':\n",
timeit.timeit(
"find_pythagorean_triplets()",
globals=globals(),
number=100,
)
)
print(
"Timing 'find_pythagorean_triplets_itertools()':\n",
timeit.timeit(
"find_pythagorean_triplets_itertools()",
globals=globals(),
number=100,
)
)
For more Python resources, you can also visit Real Python—you may even stumble on one of my own articles or courses there!
And you can find out more about me at stephengruppetta.com