Last active
December 23, 2021 03:03
-
-
Save zoiosilva/28373308471d8fed137d17af6e53b0a1 to your computer and use it in GitHub Desktop.
Recursive array items complete permutation.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"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; | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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