642 votes

Algorithme permettant de retourner toutes les combinaisons de k éléments parmi n

Je veux écrire une fonction qui prend un tableau de lettres comme argument et un nombre de ces lettres à sélectionner.

Disons que vous fournissez un tableau de 8 lettres et que vous voulez en sélectionner 3. Alors vous devriez obtenir :

8! / ((8 - 3)! * 3!) = 56

Des tableaux (ou mots) en retour composés de 3 lettres chacun.

4 votes

Une préférence pour un langage de programmation ?

9 votes

Comment voulez-vous traiter les lettres en double ?

0 votes

Pas de préférence de langage, je vais le coder en ruby mais une idée générale des algorithmes à utiliser serait bien. Deux lettres de même valeur peuvent exister mais pas la même lettre deux fois.

8voto

Andrea Ambu Points 6479

J'avais un algorithme de permutation que j'ai utilisé pour le projet euler, en python :

def missing(miss,src):
    "Returns the list of items in src not present in miss"
    return [i for i in src if i not in miss]

def permutation_gen(n,l):
    "Generates all the permutations of n items of the l list"
    for i in l:
        if n<=1: yield [i]
        r = [i]
        for j in permutation_gen(n-1,missing([i],l)):  yield r+j

Si

n<len(l) 

vous devriez avoir toute la combinaison dont vous avez besoin sans répétition, en avez-vous besoin ?

C'est un générateur, donc vous l'utilisez dans quelque chose comme ça :

for comb in permutation_gen(3,list("ABCDEFGH")):
    print comb

7voto

Akseli Palén Points 7697

https://gist.github.com/3118596

Il existe une implémentation pour JavaScript. Elle possède des fonctions pour obtenir les k-combinaisons et toutes les combinaisons d'un tableau d'objets quelconques. Exemples :

k_combinations([1,2,3], 2)
-> [[1,2], [1,3], [2,3]]

combinations([1,2,3])
-> [[1],[2],[3],[1,2],[1,3],[2,3],[1,2,3]]

7voto

Oleksandr Knyga Points 101

Disons que votre tableau de lettres ressemble à ceci : "ABCDEFGH". Vous avez trois indices (i, j, k) indiquant les lettres que vous allez utiliser pour le mot en cours, vous commencez par :

A B C D E F G H
^ ^ ^
i j k

D'abord vous faites varier k, donc l'étape suivante ressemble à ça :

A B C D E F G H
^ ^   ^
i j   k

Si vous avez atteint la fin, vous continuez et faites varier j puis k à nouveau.

A B C D E F G H
^   ^ ^
i   j k

A B C D E F G H
^   ^   ^
i   j   k

Une fois que vous avez atteint G, vous commencez également à faire varier i.

A B C D E F G H
  ^ ^ ^
  i j k

A B C D E F G H
  ^ ^   ^
  i j   k
...

function initializePointers($cnt) {
    $pointers = [];

    for($i=0; $i<$cnt; $i++) {
        $pointers[] = $i;
    }

    return $pointers;     
}

function incrementPointers(&$pointers, &$arrLength) {
    for($i=0; $i<count($pointers); $i++) {
        $currentPointerIndex = count($pointers) - $i - 1;
        $currentPointer = $pointers[$currentPointerIndex];

        if($currentPointer < $arrLength - $i - 1) {
           ++$pointers[$currentPointerIndex];

           for($j=1; ($currentPointerIndex+$j)<count($pointers); $j++) {
                $pointers[$currentPointerIndex+$j] = $pointers[$currentPointerIndex]+$j;
           }

           return true;
        }
    }

    return false;
}

function getDataByPointers(&$arr, &$pointers) {
    $data = [];

    for($i=0; $i<count($pointers); $i++) {
        $data[] = $arr[$pointers[$i]];
    }

    return $data;
}

function getCombinations($arr, $cnt)
{
    $len = count($arr);
    $result = [];
    $pointers = initializePointers($cnt);

    do {
        $result[] = getDataByPointers($arr, $pointers);
    } while(incrementPointers($pointers, count($arr)));

    return $result;
}

$result = getCombinations([0, 1, 2, 3, 4, 5], 3);
print_r($result);

Sur la base de https://stackoverflow.com/a/127898/2628125 mais plus abstrait, pour toute taille de pointeurs.

6voto

Juan Antonio Cano Points 143

Vous avez ici une version évaluée paresseusement de cet algorithme, codée en C# :

    static bool nextCombination(int[] num, int n, int k)
    {
        bool finished, changed;

        changed = finished = false;

        if (k > 0)
        {
            for (int i = k - 1; !finished && !changed; i--)
            {
                if (num[i] < (n - 1) - (k - 1) + i)
                {
                    num[i]++;
                    if (i < k - 1)
                    {
                        for (int j = i + 1; j < k; j++)
                        {
                            num[j] = num[j - 1] + 1;
                        }
                    }
                    changed = true;
                }
                finished = (i == 0);
            }
        }

        return changed;
    }

    static IEnumerable Combinations<T>(IEnumerable<T> elements, int k)
    {
        T[] elem = elements.ToArray();
        int size = elem.Length;

        if (k <= size)
        {
            int[] numbers = new int[k];
            for (int i = 0; i < k; i++)
            {
                numbers[i] = i;
            }

            do
            {
                yield return numbers.Select(n => elem[n]);
            }
            while (nextCombination(numbers, size, k));
        }
    }

Et la partie test :

    static void Main(string[] args)
    {
        int k = 3;
        var t = new[] { "dog", "cat", "mouse", "zebra"};

        foreach (IEnumerable<string> i in Combinations(t, k))
        {
            Console.WriteLine(string.Join(",", i));
        }
    }

J'espère que cela vous aidera !

5voto

oddi Points 314
Array.prototype.combs = function(num) {

    var str = this,
        length = str.length,
        of = Math.pow(2, length) - 1,
        out, combinations = [];

    while(of) {

        out = [];

        for(var i = 0, y; i < length; i++) {

            y = (1 << i);

            if(y & of && (y !== of))
                out.push(str[i]);

        }

        if (out.length >= num) {
           combinations.push(out);
        }

        of--;
    }

    return combinations;
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X