Skip to content

Instantly share code, notes, and snippets.

@zoiosilva
Last active December 23, 2021 03:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zoiosilva/28373308471d8fed137d17af6e53b0a1 to your computer and use it in GitHub Desktop.
Save zoiosilva/28373308471d8fed137d17af6e53b0a1 to your computer and use it in GitHub Desktop.
Recursive array items complete permutation.
"use strict";
/**
* Permutate all terms of the provided array.
*
* @param {any[]} terms
* The array terms to be combined.
* @param {any[]} precedence
* Some more terms to be added before the terms combination result.
*
* @return {any[]}
* An array with all possible combination of the provided terms.
*/
function termsCombination(terms, precedence = []) {
if (terms.length <= 1) {
return terms;
}
if (terms.length === 2) {
return [
[terms[0], terms[1]],
[terms[1], terms[0]],
];
}
if (terms.length !== 3) {
throw new Error('Wrong algorithm implementation.');
}
const switchPattern = [
[0,1],
[1,2],
[0,1],
[1,2],
[0,1],
];
let result = [
precedence.concat(terms)
];
switchPattern.forEach(switchers => {
const switchA = switchers[0];
const switchB = switchers[1];
let swappedA = terms[switchA];
terms[switchA] = terms[switchB];
terms[switchB] = swappedA;
result.push(precedence.concat(terms));
});
return result;
};
/**
* Arrange the array terms in all possible combinations.
*
* @param {any[]} originalTerms
* The terms array to be combined.
* @param {any[]} precedence
* Do not use it publically. Used only for internal recursion.
*
* @return {any[]}
* All possible combinations of the array terms.
*/
function permutateAll(originalTerms, precedence = []) {
const count = originalTerms.length;
if (count <= 3) {
return termsCombination(originalTerms.slice(), precedence.slice());
}
precedence.push(originalTerms[0]);
let result = permutateAll(originalTerms.slice(1), precedence.slice());
for (let i = 1; i < count; i++) {
let terms = originalTerms;
const swapped = terms[0];
terms[0] = terms[i];
terms[i] = swapped;
if (precedence.length > 1) {
precedence.pop();
precedence.push(terms[0]);
}
else {
precedence = [terms[0]];
}
result = result.concat(permutateAll(terms.slice(1), precedence.slice()));
}
return result;
};
<?php
declare(strict_types = 1);
/**
* Recursive combinatorics implementation.
*/
class Combinatorics {
/**
* Permutate all terms of the provided array.
*
* @param mixed[] $terms
* The array terms to be combined.
* @param mixed[] $precedence
* Some more terms to be added before the terms combination result.
*
* @return mixed[]
* An array with all possible combination of the provided terms.
*/
private static function termsCombination(array $terms, array $precedence = []): array {
if (count($terms) <= 1) {
return $terms;
}
if (count($terms) === 2) {
return [
[$terms[0], $terms[1]],
[$terms[1], $terms[0]],
];
}
if (count($terms) !== 3) {
throw new \Exception('Wrong algorithm implementation.');
}
$switchPattern = [
[0,1],
[1,2],
[0,1],
[1,2],
[0,1],
];
$result = [
array_merge($precedence, $terms)
];
foreach ($switchPattern as $switchers) {
$switchA = $switchers[0];
$switchB = $switchers[1];
$temp = $terms[$switchA];
$terms[$switchA] = $terms[$switchB];
$terms[$switchB] = $temp;
$result[] = array_merge($precedence, $terms);
}
return $result;
}
/**
* Arrange the array terms in all possible combinations.
*
* @param mixed[] $originalTerms
* The terms array to be combined.
* @param mixed[] $precedence
* Do not use it publically. Used only for internal recursion.
*
* @return mixed[]
* All possible combinations of the array terms.
*/
public static function permutateAll(array $originalTerms, array $precedence = []): array {
$count = count($originalTerms);
if ($count <= 3) {
return self::termsCombination($originalTerms, $precedence);
}
$precedence[] = $originalTerms[0];
$result = self::permutateAll(array_slice($originalTerms, 1), $precedence);
for ($i = 1; $i < $count; $i++) {
$terms = $originalTerms;
$temp = $terms[0];
$terms[0] = $terms[$i];
$terms[$i] = $temp;
if (count($precedence) > 1) {
array_pop($precedence);
$precedence[] = $terms[0];
}
else {
$precedence = [$terms[0]];
};
$result = array_merge($result, self::permutateAll(array_slice($terms, 1), $precedence));
}
return $result;
}
}
function testImplementationScenario(): void {
$values = ['A', 'B', 'C', 'D'];
$combinations = \Combinatorics::permutateAll($values);
foreach ($combinations as $c) {
$result .= sprintf('%s %s %s %s', $c[0], $c[1], $c[2], $c[3]) . PHP_EOL;
}
echo $result;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment