Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create possible combinations of specific size

The string/list is e.g. 'foobar'. I need to break this up in all possible combinations where the number of groups is n, e.g. 3.

This would give me e.g.

['foo', 'ba',  'r']
['f',  'ooba', 'r']
['fo', 'oo',   'bar']
['f',  'o',    'obar']

etc

What is the best algorithm to create all the possible combinations?

like image 666
Tjorriemorrie Avatar asked Feb 12 '16 11:02

Tjorriemorrie


People also ask

How do you calculate possible combinations?

Combinations are a way to calculate the total outcomes of an event where order of the outcomes does not matter. To calculate combinations, we will use the formula nCr = n! / r! * (n - r)!, where n represents the total number of items, and r represents the number of items being chosen at a time.

How do you generate all possible combinations of one list?

Add a Custom Column to and name it List1. Enter the formula =List1. Expand out the new List1 column and then Close & Load the query to a table. The table will have all the combinations of items from both lists and we saved on making a custom column in List1 and avoided using a merge query altogether!

How many combinations are possible with 5 items?

So we say that there are 5 factorial = 5! = 5x4x3x2x1 = 120 ways to arrange five objects.


2 Answers

Sounds like a job for itertools:

from itertools import combinations

def compositions(s,k):
    n = len(s)
    for c in combinations(range(1,n),k-1):
        yield [s[i:j] for i,j in zip((0,)+c,c+(n,))]

The way it works is that the combinations part yields tuples which consist of possible cut points. For example (with s = "foobar" and k = 3) (2,4) is one of the tuples. Breaking at these indices should yield ["fo","ob","ar"] which corresponds to [s[0:2],s[2,4],s[4,6]] the expression zip((0,)+c,c+(n,)) in this case is the same as zip((0,2,4),(2,4,6)) hence iterating over it has the effect of iterating over the the successive pairs of indices for the successive slices.

For example,

>>> for c in compositions("foobar",3): print(c)

['f', 'o', 'obar']
['f', 'oo', 'bar']
['f', 'oob', 'ar']
['f', 'ooba', 'r']
['fo', 'o', 'bar']
['fo', 'ob', 'ar']
['fo', 'oba', 'r']
['foo', 'b', 'ar']
['foo', 'ba', 'r']
['foob', 'a', 'r']

I chose the name "compositions" since you are essentially talking about compositions in combinatorics. My algorithm was based on the proof in the linked article that the number of compositions of n items into k pieces is C(n-1,k-1).

like image 188
John Coleman Avatar answered Oct 08 '22 18:10

John Coleman


Here is a simple recursion

def split(s, n):
    def rec_split(i, s, n):
        ans = []

        if n == 1:
            ans.append([s[i:]])
            return ans

        for j in range(i+1, len(s)):
            head = s[i:j]
            tails = rec_split(j, s, n-1)
            for tail in tails:
                ans.append([head] + tail)
        return ans

    return rec_split(0, s, n)

for e in split("foobar", 3):
    print(e)

# ['f', 'o', 'obar']
# ['f', 'oo', 'bar']
# ['f', 'oob', 'ar']
# ['f', 'ooba', 'r']
# ['fo', 'o', 'bar']
# ['fo', 'ob', 'ar']
# ['fo', 'oba', 'r']
# ['foo', 'b', 'ar']
# ['foo', 'ba', 'r']
# ['foob', 'a', 'r']

rec_split returns all partitions of s in n parts from the i-th index onward

like image 33
sve Avatar answered Oct 08 '22 20:10

sve