Determining the number of possible combinations

Question:

I’m trying to figure out how many possible ways there are to combine various elements form this string.

"{Hello|Hi|Hey} {world|earth}{!|.|?}"

Where one item (separated by a pipe/|) is selected at random from each group ({}) and combined into a single string.

So the above “template” could produce:

Hello world.
Hi earth?
Hey world.
Hi world?

I’m guessing this is a type of permutation, but I want to make sure I’m getting this right.

It would be really nice if this worked with “n” nested items as well.

"{{Hello|Hi|Hey} {world|earth}|{Goodbye|farewell} {noobs|n3wbz|n00blets}}"

I’d prefer a math/statistics based solution over brute-force looping to get the answer if possible.

Thanks!

Asked By: erikcw

||

Answers:

Well, there are 3 x 2 x 3 = 18 combinations in your first example.

Your second example is 3 x 4 x 2 x 3 = 72 combinations.

I’m not entirely sure what you mean by {a|b}|{c|d} though, I’m assuming you mean pick one of either (a or b) or (c or d), which is 4 choices.

You might want to read up on combinations here or here.


Update: Yep, it’s that simple. Your problem is exactly like counting the number of combinations of digits in a number. For example, if I want to find the number of combinations of an ATM PIN number (4 decimal digits), I have sets {0-9}, {0-9}, {0-9}, {0-9}. There are 10 possibilities for the first choice (= 10). For each of those numbers, there are 10 possibilities for the second choice (= 10 × 10). For each of those, there are 10 for the third (= 10 × 10 × 10) and 10 for the fourth (= 10 × 10 × 10 × 10 = 10,000). It should be intuitively clear that there are 10,000 possibilities for a 4 digit decimal number.

Your example uses sets of words instead of sets of digits, but the principle is the same. The number of combinations is the number of items in set 1 × number of items in set 2 × … × number of items in set n, etc.

It gets more complicated when you start putting restrictions in, or are picking multiple items from the same set, etc.

Answered By: Seth

The problem breaks down to two simple sub-problems:

  1. count how many combinations are within braces and separated within vbars, for each braces pair
  2. multiply those numbers

So for 1 I’d go with a plain regular expression + looping approach:

import re

def docount(thestring):
    x = re.compile(r'{([^}]}')
    counts = [mo.group(0).count('|')+1 for mo in x.finditer(thestring)]
    result = 1
    for c in counts: result *= c
    return result

I’ve embedded 2 as well since that’s the most trivial part anyway (if you’re keen on using reduce for such purposes, that’s OK too in lieu of the last three lines, I guess;-).

Answered By: Alex Martelli