Working With Combinations in Practice
Combinations show up constantly in real engineering work. I ran into a situation a few years back where I needed to generate every possible pairing of network switches across three different racks, but only for switches that were actually active in a given build. The theoretical count looked manageable — maybe 200 or so — but then I realized the switches weren't independent. Certain pairs were physically impossible because they shared a power distribution unit. That cut my actual valid combinations down to about 87. If I had just run the raw formula without accounting for that dependency, I would have sent out a bill of materials with nearly 120 impossible configurations. Took me about forty minutes to add the constraint filter into the script. The basic formula is nCr = n! / (r! × (n r)!). That gives you the number of ways to pick r items from a set of n when order doesn't matter. The factorial operation means you multiply a number by every positive integer below it. So 5! = 5 × 4 × 3 × 2 × 1 = 120. If you're selecting 3 from 5, you get 5! / (3! × 2!) = 120 / (6 × 2) = 10. That's it. The entire calculation reduces to a single division after you compute the three factorials. I used to think the cleanest way to remember this was to write it out fully every time. You don't need to. You can cancel terms before multiplying. For 7 choose 4, instead of computing 7! and 4! separately and then dividing, you expand only the top part down to the difference: 7 × 6 × 5. Then divide by 4 × 3 × 2. That gives you 210 / 24 = 8.75 — wait, that's wrong because I left out the (74)! part correctly as 3!. So it's 7 × 6 × 5 / (3 × 2 × 1) = 35. Canceling early keeps the numbers small and prevents overflow in spreadsheets or programming languages with fixed integer sizes.
Here's something most people miss: nCr equals nC(nr). Picking 4 people out of 10 is the same count as picking 6 people to leave behind. This isn't just a curiosity. It means you should always compute using the smaller of r or nr. If your problem has n=20 and r=17, compute 20C3 instead. The result is identical but the arithmetic is dramatically cheaper. I've seen people literally timeout scripts because they computed the long way around. Another thing that catches people out is repeated elements. The standard formula assumes every item in your set is distinct. If you're dealing with a hand of cards where suits matter but two cards of the same rank are considered identical for your purposes, the basic formula overcounts. You'd need to divide by the factorial of each group of identical items. For example, if you have 5 items where 2 are identical type A and 3 are identical type B, the adjusted count is nCr divided by (2! × 3!). This came up when I was modeling possible outcomes for a board game that used duplicate token pieces. The unadjusted combination count was about 40 percent too high.
When The Formula Breaks Down
The combination formula assumes you're sampling without replacement. If you need to pick items where repetition is allowed — say you're choosing toppings for three pizzas and you can pick the same topping more than once — you're looking at combinations with repetition, which uses a different formula: (n + r 1)Cr. People mix these up constantly. I once reviewed a configuration report where someone used the standard formula for a product bundle system that allowed duplicate items. The reported number of possible bundles was off by orders of magnitude because they had 15 options and were picking 8 with repetition allowed. The correct count was 6435. Their formula gave roughly 600. For very large values of n, computing factorials directly is impractical. 100! is a number with 158 digits. Even 200C100 would overwhelm most standard integer types. In those cases you switch to logarithmic computation or use built-in library functions. Python's math.comb handles this natively and returns arbitrary-precision integers. Excel's COMBIN function caps out reliably around n=170 before floating point precision becomes a real problem. If you're working in a constrained environment, use the multiplicative form: multiply by (nk+1)/k iteratively for k from 1 to r. This keeps intermediate results smaller and works fine up to n in the thousands with the right data type. One more edge case: what happens when r is zero or greater than n? The formula gives 1 when r=0 and 0 when r>n. That's correct but easy to miss if you're coding a loop that doesn't guard against it. I wrote a function once that returned NaN for r=0 because the loop body never executed and the accumulator variable was never initialized. Took me an hour to find because the input data had a boundary case that produced an empty selection set. Add explicit guards for r0 and rn at the top of any combination function you write.
Get the Full Details
