Here is a simple solution
Assumption:
$source = array(
'a',
'b',
'c',
'1',
'2',
'3'
);
Example 1
$c = new FindCombination($source);
echo $c->find(4,true); //returns all resul in json
echo count($c), PHP_EOL; //returns total
Example 2
If you want it sorted use
echo $c->find(4,true);
Output
[
"1",
"2",
"3",
"a",
"b",
"c",
"12",
"13",
"1a",
"1b",
"1c",
"21",
"23",
"2a",
"2b",
"2c",
"31",
"32",
"3a",
"3b",
"3c",
"a1",
"a2",
"a3",
"ab",
"ac",
"b1",
"b2",
"b3",
"ba",
"bc",
"c1",
"c2",
"c3",
"ca",
"cb",
"123",
"12a",
"12b",
"12c",
"132",
"13a",
"13b",
"13c",
"1a2",
"1a3",
"1ab",
"1ac",
"1b2",
"1b3",
"1ba",
"1bc",
"1c2",
"1c3",
"1ca",
"1cb",
"213",
"21a",
"21b",
"21c",
"231",
"23a",
"23b",
"23c",
"2a1",
"2a3",
"2ab",
"2ac",
"2b1",
"2b3",
"2ba",
"2bc",
"2c1",
"2c3",
"2ca",
"2cb",
"312",
"31a",
"31b",
"31c",
"321",
"32a",
"32b",
"32c",
"3a1",
"3a2",
"3ab",
"3ac",
"3b1",
"3b2",
"3ba",
"3bc",
"3c1",
"3c2",
"3ca",
"3cb",
"a12",
"a13",
"a1b",
"a1c",
"a21",
"a23",
"a2b",
"a2c",
"a31",
"a32",
"a3b",
"a3c",
"ab1",
"ab2",
"ab3",
"abc",
"ac1",
"ac2",
"ac3",
"acb",
"b12",
"b13",
"b1a",
"b1c",
"b21",
"b23",
"b2a",
"b2c",
"b31",
"b32",
"b3a",
"b3c",
"ba1",
"ba2",
"ba3",
"bac",
"bc1",
"bc2",
"bc3",
"bca",
"c12",
"c13",
"c1a",
"c1b",
"c21",
"c23",
"c2a",
"c2b",
"c31",
"c32",
"c3a",
"c3b",
"ca1",
"ca2",
"ca3",
"cab",
"cb1",
"cb2",
"cb3",
"cba",
"123a",
"123b",
"123c",
"12a3",
"12ab",
"12ac",
"12b3",
"12ba",
"12bc",
"12c3",
"12ca",
"12cb",
"132a",
"132b",
"132c",
"13a2",
"13ab",
"13ac",
"13b2",
"13ba",
"13bc",
"13c2",
"13ca",
"13cb",
"1a23",
"1a2b",
"1a2c",
"1a32",
"1a3b",
"1a3c",
"1ab2",
"1ab3",
"1abc",
"1ac2",
"1ac3",
"1acb",
"1b23",
"1b2a",
"1b2c",
"1b32",
"1b3a",
"1b3c",
"1ba2",
"1ba3",
"1bac",
"1bc2",
"1bc3",
"1bca",
"1c23",
"1c2a",
"1c2b",
"1c32",
"1c3a",
"1c3b",
"1ca2",
"1ca3",
"1cab",
"1cb2",
"1cb3",
"1cba",
"213a",
"213b",
"213c",
"21a3",
"21ab",
"21ac",
"21b3",
"21ba",
"21bc",
"21c3",
"21ca",
"21cb",
"231a",
"231b",
"231c",
"23a1",
"23ab",
"23ac",
"23b1",
"23ba",
"23bc",
"23c1",
"23ca",
"23cb",
"2a13",
"2a1b",
"2a1c",
"2a31",
"2a3b",
"2a3c",
"2ab1",
"2ab3",
"2abc",
"2ac1",
"2ac3",
"2acb",
"2b13",
"2b1a",
"2b1c",
"2b31",
"2b3a",
"2b3c",
"2ba1",
"2ba3",
"2bac",
"2bc1",
"2bc3",
"2bca",
"2c13",
"2c1a",
"2c1b",
"2c31",
"2c3a",
"2c3b",
"2ca1",
"2ca3",
"2cab",
"2cb1",
"2cb3",
"2cba",
"312a",
"312b",
"312c",
"31a2",
"31ab",
"31ac",
"31b2",
"31ba",
"31bc",
"31c2",
"31ca",
"31cb",
"321a",
"321b",
"321c",
"32a1",
"32ab",
"32ac",
"32b1",
"32ba",
"32bc",
"32c1",
"32ca",
"32cb",
"3a12",
"3a1b",
"3a1c",
"3a21",
"3a2b",
"3a2c",
"3ab1",
"3ab2",
"3abc",
"3ac1",
"3ac2",
"3acb",
"3b12",
"3b1a",
"3b1c",
"3b21",
"3b2a",
"3b2c",
"3ba1",
"3ba2",
"3bac",
"3bc1",
"3bc2",
"3bca",
"3c12",
"3c1a",
"3c1b",
"3c21",
"3c2a",
"3c2b",
"3ca1",
"3ca2",
"3cab",
"3cb1",
"3cb2",
"3cba",
"a123",
"a12b",
"a12c",
"a132",
"a13b",
"a13c",
"a1b2",
"a1b3",
"a1bc",
"a1c2",
"a1c3",
"a1cb",
"a213",
"a21b",
"a21c",
"a231",
"a23b",
"a23c",
"a2b1",
"a2b3",
"a2bc",
"a2c1",
"a2c3",
"a2cb",
"a312",
"a31b",
"a31c",
"a321",
"a32b",
"a32c",
"a3b1",
"a3b2",
"a3bc",
"a3c1",
"a3c2",
"a3cb",
"ab12",
"ab13",
"ab1c",
"ab21",
"ab23",
"ab2c",
"ab31",
"ab32",
"ab3c",
"abc1",
"abc2",
"abc3",
"ac12",
"ac13",
"ac1b",
"ac21",
"ac23",
"ac2b",
"ac31",
"ac32",
"ac3b",
"acb1",
"acb2",
"acb3",
"b123",
"b12a",
"b12c",
"b132",
"b13a",
"b13c",
"b1a2",
"b1a3",
"b1ac",
"b1c2",
"b1c3",
"b1ca",
"b213",
"b21a",
"b21c",
"b231",
"b23a",
"b23c",
"b2a1",
"b2a3",
"b2ac",
"b2c1",
"b2c3",
"b2ca",
"b312",
"b31a",
"b31c",
"b321",
"b32a",
"b32c",
"b3a1",
"b3a2",
"b3ac",
"b3c1",
"b3c2",
"b3ca",
"ba12",
"ba13",
"ba1c",
"ba21",
"ba23",
"ba2c",
"ba31",
"ba32",
"ba3c",
"bac1",
"bac2",
"bac3",
"bc12",
"bc13",
"bc1a",
"bc21",
"bc23",
"bc2a",
"bc31",
"bc32",
"bc3a",
"bca1",
"bca2",
"bca3",
"c123",
"c12a",
"c12b",
"c132",
"c13a",
"c13b",
"c1a2",
"c1a3",
"c1ab",
"c1b2",
"c1b3",
"c1ba",
"c213",
"c21a",
"c21b",
"c231",
"c23a",
"c23b",
"c2a1",
"c2a3",
"c2ab",
"c2b1",
"c2b3",
"c2ba",
"c312",
"c31a",
"c31b",
"c321",
"c32a",
"c32b",
"c3a1",
"c3a2",
"c3ab",
"c3b1",
"c3b2",
"c3ba",
"ca12",
"ca13",
"ca1b",
"ca21",
"ca23",
"ca2b",
"ca31",
"ca32",
"ca3b",
"cab1",
"cab2",
"cab3",
"cb12",
"cb13",
"cb1a",
"cb21",
"cb23",
"cb2a",
"cb31",
"cb32",
"cb3a",
"cba1",
"cba2",
"cba3"
]
Example 3
You can loop through the result
$c = new FindCombination($source);
foreach ( $c->find(4, true) as $v ) {
echo $v . "|";
}
Class Used
class FindCombination implements IteratorAggregate, JsonSerializable, Countable {
private $source;
private $sink = array();
private $max = 0;
function __construct(&$source) {
$this->source = $source;
}
public function jsonSerialize() {
return json_encode($this->sink, 128);
}
public function getIterator() {
return new ArrayIterator($this->sink);
}
public function count() {
return count($this->sink);
}
public function __toString() {
return $this->jsonSerialize();
}
public function find($max = 0, $sort = false) {
$this->sink = array(); // reset sink
$this->max = $max;
$this->parse($this->source);
if ($sort) {
usort($this->sink, function ($a, $b) {
$al = strlen($a);
$bl = strlen($b);
return $al == $bl ? strcmp($a, $b) : strcmp($al, $bl);
});
}
return $this;
}
private function parse($source, $tempString = "") {
if ($tempString != "")
$this->sink[] = $tempString;
for($i = 0; $i < count($source); $i ++) {
$copy = $source;
$elem = array_splice($copy, $i, 1);
$tempModified = $tempString . $elem[0];
if (strlen($tempModified) > $this->max && $this->max > 0)
continue;
if (count($copy) > 0) {
$this->parse($copy, $tempModified);
} else {
$this->sink[] = $tempModified;
}
}
}
}