3

Suppose an array is

Array
(
    [0] => 1
    [1] => 2
    [2] => 3
    [3] => 4
)

I want to call a function by providing two params (both arrays) with following permutations -

array(1) and array(2,3,4)
array(1,2) and array(3,4)
array(1,2,3) and array (4)
array(1,3) and array(2,4)
array(1,4) and array(2,3)
array(2) and array(1,3,4)
and so on...

Of course the actual arrays will be larger.

Dr.Kameleon
  • 22,532
  • 20
  • 115
  • 223
kapeels
  • 1,692
  • 4
  • 30
  • 52
  • 6
    So you want to call a function, passing in those arrays, what are you expecting the result to be? Please show example input **and** output. – DaveRandom Apr 13 '12 at 16:52
  • 1
    Those look more like equivalence classes than permutations – Paul Apr 13 '12 at 16:52
  • 3
    Check this : [PHP code to generate all the combinations of a set of elements](http://www.sonyjose.in/blog/?p=62) – safarov Apr 13 '12 at 17:13

3 Answers3

2

I don't know how that "permutation" is called (it's not a permutation even probably), but it looked promising to me exploiting the fact that the elements in the set are ordered (if not, there is the order of index, so use index instead of value) so to shift from right to left and combine all left with right combinations.

This is either possible with recursion or with a stack, I normally prefer the stack.

The usage as suggested (encapsulating the function call):

$funky = function($a, $b) {
    printf("(%s) and (%s)\n", implode(',', $a), implode(',', $b));
};

$paired = function($function) {
    return function(array $array) use ($function) {
        ...
    };
};


$funkyAll = $paired($funky);
$funkyAll(range(1, 5));

Running this with a sorted (more memory required) stack consuming strategy gives the following output (formatted in columns):

(1) and (2,3,4,5)    (2,4) and (1,3,5)    (1,4,5) and (2,3)
(2) and (1,3,4,5)    (2,5) and (1,3,4)    (2,3,4) and (1,5)
(3) and (1,2,4,5)    (3,4) and (1,2,5)    (2,3,5) and (1,4)
(4) and (1,2,3,5)    (3,5) and (1,2,4)    (2,4,5) and (1,3)
(5) and (1,2,3,4)    (4,5) and (1,2,3)    (3,4,5) and (1,2)
(1,2) and (3,4,5)    (1,2,3) and (4,5)    (1,2,3,4) and (5)
(1,3) and (2,4,5)    (1,2,4) and (3,5)    (1,2,3,5) and (4)
(1,4) and (2,3,5)    (1,2,5) and (3,4)    (1,2,4,5) and (3)
(1,5) and (2,3,4)    (1,3,4) and (2,5)    (1,3,4,5) and (2)
(2,3) and (1,4,5)    (1,3,5) and (2,4)    (2,3,4,5) and (1)

The exemplary implementation (full source-code as gist) is memory optimized and produces this order (array_pop instead of array_shift):

(1) and (2,3,4,5)    (2,4) and (1,3,5)    (1,4,5) and (2,3)
(2) and (1,3,4,5)    (2,5) and (1,3,4)    (1,3,4) and (2,5)
(3) and (1,2,4,5)    (2,4,5) and (1,3)    (1,3,5) and (2,4)
(4) and (1,2,3,5)    (2,3,4) and (1,5)    (1,3,4,5) and (2)
(5) and (1,2,3,4)    (2,3,5) and (1,4)    (1,2,3) and (4,5)
(4,5) and (1,2,3)    (2,3,4,5) and (1)    (1,2,4) and (3,5)
(3,4) and (1,2,5)    (1,2) and (3,4,5)    (1,2,5) and (3,4)
(3,5) and (1,2,4)    (1,3) and (2,4,5)    (1,2,4,5) and (3)
(3,4,5) and (1,2)    (1,4) and (2,3,5)    (1,2,3,4) and (5)
(2,3) and (1,4,5)    (1,5) and (2,3,4)    (1,2,3,5) and (4)

Implementation:

$stack[] = array(array(), $array);
while (list($left, $right) = array_pop($stack)) {
    $min = end($left);
    foreach ($right as $value)
    {
        if ($value < $min) continue;
        $left2 = array_merge($left, array($value));
        $right2 = array_diff($right, $left2);
        if (!($left2 && $count = count($right2))) continue;
        $function($left2, $right2);
        --$count && $stack[] = array($left2, $right2);
    }
}

I hope this is useful.

Another array related algorithm: Sorting with a modulus (just for reference, while writing this one I was reminded to that matrix thing)

Community
  • 1
  • 1
hakre
  • 193,403
  • 52
  • 435
  • 836
  • Ref: [all string combinations in a fixed length, based on a charset](http://stackoverflow.com/a/7891640/367456) – hakre Sep 29 '12 at 09:28
1

how about using array_pop with array_merge

chk this url

http://php.net/manual/en/function.array-pop.php

and use sarafov's suggestion with the url

http://www.sonyjose.in/blog/?p=62

something like

foreach($combinations as $combination)
    while(in_array($combination)){
        $arr = array_pop($combination);
        foo($fruit , $combination); 
    }
}
Sandeep Rajoria
  • 1,243
  • 8
  • 14
1

I think this is what you need.

Code :

<?php

function combinations($arr, $n)
{
    $res = array();

    foreach ($arr[$n] as $item)
    {
        if ($n==count($arr)-1)
            $res[]=$item;
        else
        {
            $combs = combinations($arr,$n+1);

            foreach ($combs as $comb)
            {
                $res[] = "$item $comb";
            }
        }
    }
    return $res;
}

// Your ARRAY
//
// you can put as many items in each subarray as you like... 
// and as many subarrays as you like
$words = array(array('A','B'),array('C','D'), array('E','F'));

$combos = combinations($words,0);  // ALWAYS, call it with 0 as the last parameter
print_r($combos);

?>

Output :

Array
(
    [0] => A C E
    [1] => A C F
    [2] => A D E
    [3] => A D F
    [4] => B C E
    [5] => B C F
    [6] => B D E
    [7] => B D F
)

Usage : (like in your example)

$combos = combinations(array(array(1,4),array(2,3)));
Dr.Kameleon
  • 22,532
  • 20
  • 115
  • 223