web-dev-qa-db-fra.com

PHP algorithme pour générer toutes les combinaisons d'une taille spécifique à partir d'un seul ensemble

J'essaie de déduire un algorithme qui génère toutes les combinaisons possibles d'une taille spécifique, quelque chose comme une fonction qui accepte un tableau de caractères et de taille comme paramètre et renvoie un tableau de combinaisons.

Exemple: disons que nous avons un ensemble de caractères: ensemble A = {A, B, C}

a) Toutes les combinaisons possibles de taille 2: (3 ^ 2 = 9)

AA, AB, AC
BA, BB, BC
CA, CB, CC

b) Toutes les combinaisons possibles de taille 3: (3 ^ 3 = 27)

AAA, AAB, AAC,
ABA, ABB, ACC,
CAA, BAA, BAC,
.... ad so on total combinations = 27

Veuillez noter que la taille de la paire peut être supérieure à la taille totale de la poche. Ex. si l'ensemble contient 3 caractères, nous pouvons également créer une combinaison de taille 4.

EDIT : Notez également que ceci est différent de la permutation. En permutation, nous ne pouvons pas avoir de caractères répétitifs, par exemple AA ne peut pas venir si nous utilisons l'algorithme de permutation. En statistique, il est connu sous le nom d'échantillonnage.

30
asim-ishaq

J'utiliserais une fonction récursive. Voici un exemple (fonctionnel) avec des commentaires. J'espère que cela fonctionne pour toi!

function sampling($chars, $size, $combinations = array()) {

    # if it's the first iteration, the first set 
    # of combinations is the same as the set of characters
    if (empty($combinations)) {
        $combinations = $chars;
    }

    # we're done if we're at size 1
    if ($size == 1) {
        return $combinations;
    }

    # initialise array to put new values in
    $new_combinations = array();

    # loop through existing combinations and character set to create strings
    foreach ($combinations as $combination) {
        foreach ($chars as $char) {
            $new_combinations[] = $combination . $char;
        }
    }

    # call same function again for the next iteration
    return sampling($chars, $size - 1, $new_combinations);

}

// example
$chars = array('a', 'b', 'c');
$output = sampling($chars, 2);
var_dump($output);
/*
array(9) {
  [0]=>
  string(2) "aa"
  [1]=>
  string(2) "ab"
  [2]=>
  string(2) "ac"
  [3]=>
  string(2) "ba"
  [4]=>
  string(2) "bb"
  [5]=>
  string(2) "bc"
  [6]=>
  string(2) "ca"
  [7]=>
  string(2) "cb"
  [8]=>
  string(2) "cc"
}
*/
45
Joel Hinz

Vous pouvez le faire récursivement. Notez que selon votre définition, les "combinaisons" de longueur n+1 peut être généré à partir des combinaisons de longueur n en prenant chaque combinaison de longueur n et en ajoutant une des lettres de votre ensemble. Si vous vous souciez, vous pouvez le prouver par induction mathématique .

Ainsi, par exemple, avec un ensemble de {A,B,C} les combinaisons de longueur 1 sont:

A, B, C

Les combinaisons de longueur 2 sont donc

(A, B, C) + A = AA, BA, CA
(A, B, C) + B = AB, BB, BC
(A, B, C) + C = AC, CB, CC

Ce serait le code et ici sur ideone

function comb ($n, $elems) {
    if ($n > 0) {
      $tmp_set = array();
      $res = comb($n-1, $elems);
      foreach ($res as $ce) {
          foreach ($elems as $e) {
             array_Push($tmp_set, $ce . $e);
          }
       }
       return $tmp_set;
    }
    else {
        return array('');
    }
}
$elems = array('A','B','C');
$v = comb(4, $elems);
5
cyon

Un algorithme possible serait:

$array_elems_to_combine = array('A', 'B', 'C');
$size = 4;
$current_set = array('');

for ($i = 0; $i < $size; $i++) {
    $tmp_set = array();
    foreach ($current_set as $curr_elem) {
        foreach ($array_elems_to_combine as $new_elem) {
            $tmp_set[] = $curr_elem . $new_elem;
        }
    }
    $current_set = $tmp_set;
}

return $current_set;

Fondamentalement, ce que vous allez faire est de prendre chaque élément de l'ensemble actuel et d'ajouter tous les éléments du tableau d'éléments.

Dans la première étape: vous aurez comme résultat ('a', 'b', 'c'), après l'étape des secondes: ('aa', 'ab', 'ac', 'ba', 'bb', 'bc', 'ca', 'cb', 'cc') etc.

4
Santiago Alessandri

Une autre idée en utilisant la conversion de base numérique

$items = ['a', 'b', 'c', 'd'];
$length = 3;
$numberOfSequences = pow(count($items), $length);
for ($i = 0; $i < $numberOfSequences; $i++) {
    $results[] = array_map(function ($key) use ($items) {
        return $items[base_convert($key, count($items), 10)];
    }, str_split(str_pad(base_convert($i, 10, count($items), $length, 0, STR_PAD_LEFT)));
}

return $results;
0
user1913526