Generating permutations from arrays - php

I tried to port a function that generates permutations from this answer to PHP and I came out with the following:
function recurse($s, $arrs, $k) {
if ($k === count($arrs)) {
echo $s.' ';
} else {
foreach ($arrs[$k] as $o) {
recurse($s.$o, $arrs, $k + 1);
}
}
}
which gives me the correct output 137 138 147 148 237 238 247 248
Now I want to have the output as an array and not as a string, but after the edit for some reason I get wrong results:
function generatePermutations($s, $arrs, $k) {
if ($k === count($arrs)) {
print_r($s);
} else {
foreach ($arrs[$k] as $o) {
$s[] = $o;
generatePermutations($s, $arrs, $k + 1);
}
}
}
Output:
Array
(
[0] => 1
[1] => 3
[2] => 7
)
Array
(
[0] => 1
[1] => 3
[2] => 7
[3] => 8
)
Array
(
[0] => 1
[1] => 3
[2] => 4
[3] => 7
)
Array
(
[0] => 1
[1] => 3
[2] => 4
[3] => 7
[4] => 8
)
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 7
)
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 7
[4] => 8
)
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
[4] => 7
)
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
[4] => 7
[5] => 8
)
This is the input for both functions
$in = array( array(1, 2), array(3, 4), array(7, 8) );
recurse("", $in, 0);
generatePermutations(array(), $in, 0);
What did I do wrong?

if you use $s[] = $o; in your recursive function, it will slice your array for every digit.
You can add a "result" parameter, which will hold your resultset as an array.
Notice the & sign. Without it, the parameter is not "writable", only "readable".
$in = array( array(1, 2), array(3, 4), array(7, 8) );
$result = array();
generatePermutations("", $in, 0, $result);
print_r($result);
function generatePermutations($s, $arrs, $k, &$result) {
if ($k === count($arrs)) {
$result[] = $s;
} else {
foreach ($arrs[$k] as $o) {
generatePermutations($s.$o, $arrs, $k + 1, $result);
}
}
}
Output :
Array
(
[0] => 137
[1] => 138
[2] => 147
[3] => 148
[4] => 237
[5] => 238
[6] => 247
[7] => 248
)
Edit : Modification to get Robotex's expected output :
$in = array( array(1, 2), array(3, 4), array(7, 8) );
$result = array();
$s = array();
generatePermutations($s, $in, 0, $result);
print_r($result);
function generatePermutations(&$s, $arrs, $k, &$result) {
if ($k === count($arrs)) {
array_push($result, $s);
} else {
foreach ($arrs[$k] as $o) {
array_push($s, $o);
generatePermutations($s, $arrs, $k + 1, $result);
array_pop($s);
}
}
}
Output :
Array
(
[0] => Array
(
[0] => 1
[1] => 3
[2] => 7
)
[1] => Array
(
[0] => 1
[1] => 3
[2] => 8
)
[2] => Array
(
[0] => 1
[1] => 4
[2] => 7
)
[3] => Array
(
[0] => 1
[1] => 4
[2] => 8
)
[4] => Array
(
[0] => 2
[1] => 3
[2] => 7
)
[5] => Array
(
[0] => 2
[1] => 3
[2] => 8
)
[6] => Array
(
[0] => 2
[1] => 4
[2] => 7
)
[7] => Array
(
[0] => 2
[1] => 4
[2] => 8
)
)

Related

Concatenate value elements of two or more different arrays in PHP

I originally have this array
Array
(
[0] => Amministrativo ^25^9,11,2,10,18,4,7,^17,13,^0.75^0^0.25
[1] => Logico deduttive^7^^21,^0.75^0^-0.25
[2] => Situazionali^8^^20,^0.75^0^0.375
)
Using the function explode and array_diff i can get to this
Array
(
[0] => Amministrativo
[1] => 25
[2] => 9,11,2,10,18,4,7,
[3] => 17,13,
[4] => 0.75
[5] => 0
[6] => 0.25
)
Array
(
[0] => Logico deduttive
[1] => 7
[2] =>
[3] => 21,
[4] => 0.75
[5] => 0
[6] => -0.25
)
Array
(
[0] => Situazionali
[1] => 8
[2] =>
[3] => 20,
[4] => 0.75
[5] => 0
[6] => 0.375
)
but I would like to concatenate the elements of each array to get a unique array. I think I need to use the array_map function but I don't know how. This below is the result I would like to achieve
Array (
[0] => Amministrativo Logico deduttive Situazionali
[1] => 25 7 8
[2] => 9,11,2,10,18,4,7,
[3] => 17,13,21,20,
[4] => 0.75 0.75 0.75
[5] => 0 0 0
[6] => 0.25 -0.25 0.375
)
tnks
EDIT:
I tried the code that is here and it is fine.
But now I realized that there is also the problem that the arrays can be in variable number 1, 2, 3 or more and I can't know it before, I should adapt this code
$result = array_map(function ($item1, $item2,$item3) {
return "$item1 $item2 $item3";
}, $test[0], $test[1],$test[2]);
The lines of the original array are split with explode. The result is a two-dimensional array. This is transposed (swapping rows and columns). Then the lines are reassembled with implode.
function array_transpose(array $a) {
$r = array();
foreach($a as $keyRow => $subArr) {
foreach($subArr as $keyCol => $value) $r[$keyCol][$keyRow] = $value;
}
return $r;
}
$arr = [
'Amministrativo ^25^9,11,2,10,18,4,7,^17,13,^0.75^0^0.25',
'Logico deduttive^7^^21,^0.75^0^-0.25',
'Situazionali^8^^20,^0.75^0^0.375',
];
foreach($arr as $i => $row){
$arr[$i] = explode('^',$row);
}
$arr = array_transpose($arr);
foreach($arr as $i => $row){
$arr[$i] = implode(' ',$row);
}
var_export($arr);
Demo: https://3v4l.org/IdsDh

Combined Strings and sum numeric two multidimensional arrays in PHP

I have below two arrays with strings and numbers,
I want to keep only one strings header and sum numeric value from each key value with another array.
I have tried many of the solutions available online but nothing found as required.
$array1 =
Array
(
[0] => Array
(
[0] => Out Of Warranty
[1] => Total Orders
[2] => Total Qty
[3] => Canceled Orders
)
[1] => Array
(
[0] => Today<br/>(04-26-2020)
[1] => 1
[2] => 1
[3] => 0
)
[2] => Array
(
[0] => Yesterday<br/>(04-25-2020)
[1] => 0
[2] => 0
[3] => 0
)
[3] => Array
(
[0] => This Week<br/>(04-20-2020 - 04-26-2020)
[1] => 22
[2] => 39
[3] => 0
)
[4] => Array
(
[0] => Last Week<br/>(04-13-2020 - 04-19-2020)
[1] => 7
[2] => 7
[3] => 0
)
[5] => Array
(
[0] => This Month<br/>(04-01-2020 - 04-26-2020)
[1] => 29
[2] => 46
[3] => 0
)
[6] => Array
(
[0] => This Year<br/>(01-01-2020 - 04-26-2020)
[1] => 30
[2] => 47
[3] => 0
)
)
$array2 =
Array
(
[0] => Array
(
[0] => Out Of Warranty
[1] => Total Orders
[2] => Total Qty
[3] => Canceled Orders
)
[1] => Array
(
[0] => Today<br/>(04-24-2020)
[1] => 10
[2] => 10
[3] => 0
)
[2] => Array
(
[0] => Yesterday<br/>(04-23-2020)
[1] => 7
[2] => 7
[3] => 0
)
[3] => Array
(
[0] => This Week<br/>(04-20-2020 - 04-24-2020)
[1] => 51
[2] => 51
[3] => 0
)
[4] => Array
(
[0] => Last Week<br/>(04-13-2020 - 04-19-2020)
[1] => 31
[2] => 31
[3] => 0
)
[5] => Array
(
[0] => This Month<br/>(04-01-2020 - 04-24-2020)
[1] => 93
[2] => 93
[3] => 0
)
[6] => Array
(
[0] => This Year<br/>(01-01-2020 - 04-24-2020)
[1] => 1281
[2] => 1281
[3] => 1
)
)
Expected output as Strings should be use only once and numbers should be added to each other.
For example output should be 6 index i.e sum of 6 index from array1 and array2 -
[6] => Array
(
[0] => This Year<br/>(01-01-2020 - 04-26-2020)
[1] => 1311
[2] => 1328
[3] => 1
)
If your arrays are always sorted in the same order:
$newItems = [];
foreach ($array1 as $key => $item) {
$newItems[] = [
$item[0],
$item[1] + $array2[$key][1],
$item[2] + $array2[$key][2],
$item[3] + $array2[$key][3],
];
}
If keys in arrays are in distinct orders:
$newItems = [];
foreach ($array1 as $item) {
$name = $item[0];
$newItems[$name] = $item;
}
foreach ($array2 as $item) {
$name = $item[0];
$newItems[$name][1] += $item[1];
$newItems[$name][2] += $item[2];
$newItems[$name][3] += $item[3];
}
// apply array_values to get 0-indexed array
$newItems = array_values($newItems);
Only iterate the elements that are necessary for your summing logic. Using 2 loops will be the most concise and deliberate way to sum columns [1], [2], and [3].
You can create a new output array, but merely adding the second array values to the first affords a simpler addition-assignment syntax.
Code: (Demo)
for ($i = 1, $size = count($array2); $i < $size; ++$i) { // don't iterate [0] subarray (headers)
for ($col = 1; $col <= 3; ++$col) { // don't iterate [0] element (name)
$array1[$i][$col] += $array2[$i][$col];
}
}
var_export($array1);
Output:
array (
0 =>
array (
0 => 'Out Of Warranty',
1 => 'Total Orders',
2 => 'Total Qty',
3 => 'Canceled Orders',
),
1 =>
array (
0 => 'Today<br/>(04-26-2020)',
1 => 11,
2 => 11,
3 => 0,
),
2 =>
array (
0 => 'Yesterday<br/>(04-25-2020)',
1 => 7,
2 => 7,
3 => 0,
),
3 =>
array (
0 => 'This Week<br/>(04-20-2020 - 04-26-2020)',
1 => 73,
2 => 90,
3 => 0,
),
4 =>
array (
0 => 'Last Week<br/>(04-13-2020 - 04-19-2020)',
1 => 38,
2 => 38,
3 => 0,
),
5 =>
array (
0 => 'This Month<br/>(04-01-2020 - 04-26-2020)',
1 => 122,
2 => 139,
3 => 0,
),
6 =>
array (
0 => 'This Year<br/>(01-01-2020 - 04-26-2020)',
1 => 1311,
2 => 1328,
3 => 1,
),
)

Combinations from an array in set of 6 but not reverse unique

I am trying to figure out a function to get sets of 6 from an array.
I want to get every combination but not the unique combination.
For example if 1,2,3,4,5,6 already exsist 4,5,6,1,2,3 is not needed.
I just want the set of 6 possible combinations that will cover all numbers in the array.
Thank you for the help and your time.
I have tried:
function pc_permute($items, $perms = [], &$ret = []) {
if (empty($items)) {
$ret[] = $perms;
} else {
for ($i = count($items) - 1; $i >= 0; --$i) {
$newitems = $items;
$newperms = $perms;
list($foo) = array_splice($newitems, $i, 1);
array_unshift($newperms, $foo);
$this->pc_permute($newitems, $newperms,$ret);
}
}
return $ret;
}
but this is not what I want
my array is like:
$array = array(1,2,3,4,5,6,7,8,9);
One way to go about this is to shuffle() your array. Then copy the array using array_slice() from 0 - 5, 1 - 6, etc...
$arr = [1,2,3,4,5,6,7,8,9];
shuffle($arr);
$result = [];
for ($x = 0; $x < 6; $x++) {
$temp = array_slice($arr, $x, 6);
if ( count( $temp ) < 6 ) $temp = array_merge( $temp, array_slice($arr, 0, 6 - count( $temp ) ) );
shuffle($temp);
$result[] = $temp;
}
echo "<pre>";
print_r( $result );
echo "</pre>";
Sample output:
Array
(
[0] => Array
(
[0] => 8
[1] => 2
[2] => 7
[3] => 3
[4] => 6
[5] => 5
)
[1] => Array
(
[0] => 3
[1] => 8
[2] => 5
[3] => 7
[4] => 1
[5] => 2
)
[2] => Array
(
[0] => 1
[1] => 3
[2] => 4
[3] => 5
[4] => 2
[5] => 7
)
[3] => Array
(
[0] => 7
[1] => 5
[2] => 9
[3] => 1
[4] => 4
[5] => 3
)
[4] => Array
(
[0] => 4
[1] => 5
[2] => 6
[3] => 7
[4] => 9
[5] => 1
)
[5] => Array
(
[0] => 6
[1] => 8
[2] => 1
[3] => 9
[4] => 7
[5] => 4
)
)

Find all possible permutations without repeating the value

Let's say I have this set of arrays as input:
[
0 => [1,2,4,5],
1 => [2,3,4],
2 => [1,3],
]
I would like to find all permutations possible selecting one value from each array. That value would be unique in the final result, so it won't repeat. For example, I can't have 1 twice in the result.
The count of arrays on input is the same as count of arrays on output.
Examples of combinations wanted (key=>value):
[0 => 1,1 => 2,2 => 3]
[0 => 2,1 => 3,2 => 1]
[0 => 5,1 => 2,2 => 1]
[0 => 1,1 => 3,2 => null]
Wrong results
[0 => 1,1 => 2,2 => 1]
or
[0 => 2,1 => 2,2 => 3]
I would like to get set of all possible permutations using PHP. How can I do that?
I have attached real data set http://pastebin.com/U6Hyawm4 However, I have no idea how many permutations there may be.
Here's a non-recursive version that's also optimized
/**
* Generates all the possible unique N-tuples from an array of N arrays of integers
*
* #param array $input
* #return array
*/
function generateCombinations(array &$input) {
// since the example results included [1, 3, null] I have assumed that
// null is a possible value of each set.
$sets = [];
foreach($input as $set) {
if(!in_array(null, $set)) {
$set[] = null;
}
$sets[] = $set;
}
// by working on the iterators of each array this loop
// linearizes the entire set of possible combinations
// and iterates it (skipping as many as it can).
$output = [];
$setCount = count($sets);
while(current($sets[0]) !== false) {
$testCombo = [];
for($setIdx = 0; $setIdx < $setCount; $setIdx++) {
if(!in_array(current($sets[$setIdx]), $testCombo)) {
$testCombo[] = current($sets[$setIdx]);
}
else {
// when a combination is thrown out as duplicate
// iterate to skip any other combo's that would also
// contain that duplicate
iterateSets($sets, $setIdx);
break;
}
}
// if there were no duplicates add it to the output and iterate
if(count($testCombo) == $setCount) {
$output[] = $testCombo;
iterateSets($sets, $setCount - 1);
}
}
return $output;
}
/**
* Iterates to the next potentially valid combination. I think of
* this like doing long-hand addition. Add 1 and carry is akin to
* next and reset.
*
* #param array $sets
* #param $index
*/
function iterateSets(array &$sets, $index) {
// reset iterators of all sets past the current one to skip
// combos that cannot be valid
for($i = $index + 1, $ic = count($sets); $i < $ic; $i++) {
reset($sets[$i]);
}
// always move one on current set
next($sets[$index]);
while($index > 0 && current($sets[$index]) === false) {
// wrap if current set is at the end
reset($sets[$index]);
$index--;
// move one for the preceding set
next($sets[$index]);
// then repeat
}
}
The resulting array is:
[
[1,2,3]
[1,2,null]
[1,3,null]
[1,4,3]
[1,4,null]
[1,null,3]
[2,3,1]
[2,3,null]
[2,4,1]
[2,4,3]
[2,4,null]
[2,null,1]
[2,null,3]
[4,2,1]
[4,2,3]
[4,2,null]
[4,3,1]
[4,3,null]
[4,null,1]
[4,null,3]
[5,2,1]
[5,2,3]
[5,2,null]
[5,3,1]
[5,3,null]
[5,4,1]
[5,4,3]
[5,4,null]
[5,null,1]
[5,null,3]
[null,2,1]
[null,2,3]
[null,3,1]
[null,4,1]
[null,4,3]
]
Here's an inefficient version:
$input = array(
[1,2,4,5],
[2,3,4],
[1,3]
);
function appendUnique($subs, $i) {
global $input;
if ($i == count($input)) {
return $subs;
}
$output = array();
foreach ($subs as $sub) {
foreach ($input[$i] as $v) {
$new_sub = array_values($sub);
if (in_array($v, $sub)) {
$new_sub[] = null;
} else {
$new_sub[] = $v;
}
$output[] = $new_sub;
}
}
return appendUnique($output, $i+1);
}
$output = appendUnique([[]], 0);
$output_json = array();
foreach ($output as $row) {
$output_json[] = json_encode($row);
}
$output_json = array_unique($output_json);
$deduped = array();
foreach ($output_json as $json) {
$deduped[] = json_decode($json);
}
print_r($deduped);
outputs:
Array
(
[0] => Array
(
[0] => 1
[1] => 2
[2] =>
)
[1] => Array
(
[0] => 1
[1] => 2
[2] => 3
)
[2] => Array
(
[0] => 1
[1] => 3
[2] =>
)
[3] => Array
(
[0] => 1
[1] => 4
[2] =>
)
[4] => Array
(
[0] => 1
[1] => 4
[2] => 3
)
[5] => Array
(
[0] => 2
[1] =>
[2] => 1
)
[6] => Array
(
[0] => 2
[1] =>
[2] => 3
)
[7] => Array
(
[0] => 2
[1] => 3
[2] => 1
)
[8] => Array
(
[0] => 2
[1] => 3
[2] =>
)
[9] => Array
(
[0] => 2
[1] => 4
[2] => 1
)
[10] => Array
(
[0] => 2
[1] => 4
[2] => 3
)
[11] => Array
(
[0] => 4
[1] => 2
[2] => 1
)
[12] => Array
(
[0] => 4
[1] => 2
[2] => 3
)
[13] => Array
(
[0] => 4
[1] => 3
[2] => 1
)
[14] => Array
(
[0] => 4
[1] => 3
[2] =>
)
[15] => Array
(
[0] => 4
[1] =>
[2] => 1
)
[16] => Array
(
[0] => 4
[1] =>
[2] => 3
)
[17] => Array
(
[0] => 5
[1] => 2
[2] => 1
)
[18] => Array
(
[0] => 5
[1] => 2
[2] => 3
)
[19] => Array
(
[0] => 5
[1] => 3
[2] => 1
)
[20] => Array
(
[0] => 5
[1] => 3
[2] =>
)
[21] => Array
(
[0] => 5
[1] => 4
[2] => 1
)
[22] => Array
(
[0] => 5
[1] => 4
[2] => 3
)
)

PHP array - Sum value of the same key when key are number [duplicate]

This question already has answers here:
PHP Array Group by one field and Sum up two fields [duplicate]
(2 answers)
Closed 4 months ago.
My situation is similar to this thread :
Associative array, sum values of the same key
However in my case all keys are number.
I would like to reduce / combine array where key 0 is similar and make a sum of all other keys.
Here is my original array :
Array
(
[0] => Array
(
[0] => 093042
[1] => 3
[2] => 0
[4] => 0
)
[1] => Array
(
[0] => 222032
[1] => 0
[2] => 13
[4] => 0
)
[2] => Array
(
[0] => 222032
[1] => 0
[2] => 0
[4] => 15
)
[3] => Array
(
[0] => 152963
[1] => 45
[2] => 0
[4] => 0
)
[4] => Array
(
[0] => 222032
[1] => 0
[2] => 7
[4] => 0
)
)
and here is the output i need :
Array
(
[0] => Array
(
[0] => 093042
[1] => 3
[2] => 0
[4] => 0
)
[1] => Array
(
[0] => 222032
[1] => 0
[2] => 20
[4] => 15
)
[2] => Array
(
[0] => 152963
[1] => 45
[2] => 0
[4] => 0
)
)
The solution of other thread is not working because they use the key name and i don't know how i can adapt this to my situation.
Please if you can give me an example of working solution.
REPLY :
For now i try something like that : Take from other thread
$sum = array_reduce($data, function ($a, $b) {
if (isset($a[$b[0]])) {
$a[$b[0]]['budget'] += $b['budget'];
}
else {
$a[$b[0]] = $b;
}
return $a;
});
But this example look is only for key named budget but in my case is number and i have 3 key [1] [2] [3] how can't sum key 1,2,4 where key 0 is similar
This should work for you:
Basically I just loop through your array and check if there is already an element in $result with the key of the first element of $v. If not I initialize it with an array_pad()'ed array of 0's + the current array of the iteration of the foreach loop.
And after this I loop through each element of $v expect the first one and add it to the result array.
At the end I just reindex the result array with array_values().
<?php
foreach($arr as $v){
if(!isset($result[$v[0]]))
$result[$v[0]] = array_pad([$v[0]], count($v), 0);
$count = count($v);
for($i = 1; $i < $count; $i++)
$result[$v[0]][$i] += $v[$i];
}
$result = array_values($result);
print_r($result);
?>
output:
Array
(
[0] => Array
(
[0] => 093042
[1] => 3
[2] => 0
[3] => 0
)
[1] => Array
(
[0] => 222032
[1] => 0
[2] => 20
[3] => 15
)
[2] => Array
(
[0] => 152963
[1] => 45
[2] => 0
[3] => 0
)
)
try this
$data = Array
(
0 => Array
(
0 => 93042,
1 => 3,
2 => 0,
4 => 0,
),
1 => Array
(
0 => 222032,
1 => 0,
2 => 13,
4 => 0,
),
2 => Array
(
0 => 222032,
1 => 0,
2 => 0,
4 => 15,
),
3 => Array
(
0 => 152963,
1 => 45,
2 => 0,
4 => 0,
),
4 => Array
(
0 => 222032,
1 => 0,
2 => 7,
4 => 0,
),
);
var_dump($data);
// grouping
$tab1 = array();
foreach ($data as $e) {
if (!isset($tab1[$e[0]])) {
$tab1[$e[0]] = array();
}
$tab1[$e[0]][] = $e;
}
//var_dump($tab1);
// summing
$tabSum = array();
foreach ($tab1 as $id => $t) {
foreach ($t as $e) {
unset($e[0]);
if (!isset($tabSum[$id])) {
$tabSum[$id] = $e;
} else {
foreach ($e as $key => $value) {
$tabSum[$id][$key] += $value;
}
}
}
}
var_dump($tabSum);

Categories