Combine array elements - php

I want to loop through 3 arrays to create 1 single array with all 3 values in them.
See below for example and outcome.
Input:
array(
'0' => array(
'0' => array('a'),
'1' => array('b')
),
'1' => array(
'0' => array('c'),
'1' => array('d'),
'2' => array('e')
),
'2' => array(
'0' => array('f')
),
)
Outcome:
array(
'0' => 'acf',
'1' => 'adf',
'2' => 'aef',
'3' => 'bcf',
'4' => 'bdf',
'5' => 'bef'
)

Funnily I had the same problem a couple of years ago, so here's the solution I then came up with.
public static function combineElementsSuccessive($arry)
{
$result = [];
if (empty($arry) || !is_array($arry)) {
return result;
}
self::concatAndPush('', $result, $arry, 0);
return $result;
}
private static function concatAndPush($str, &$res_arry, $arry, $index)
{
foreach ($arry[$index] as $key => $val) {
$mod_str = $str . $val;
if (isset($arry[$index+1])) {
self::concatAndPush($mod_str, $res_arry, $arry, $index+1);
}
else {
$res_arry[] = $mod_str;
}
}
}
See it in action
Nevermind the static methods, I had to integrate them somehow in an application full of legacy code ;-)

How about this?
// $old_array = your original array
$new_array=array();
for ($i=0; $i<count($old_array[0]); $i++) {
for ($j=0; $j<count($old_array[1]); $j++) {
for ($k=0; $k<count($old_array[2]); $k++) {
$new_array[]=$old_array[0][$i].$old_array[1][$j].$old_array[2][$k];
}
}
}
var_dump($new_array);
It returns:
array(6) { [0]=> string(3) "acf" [1]=> string(3) "adf" [2]=> string(3) "aef" [3]=> string(3) "bcf" [4]=> string(3) "bdf" [5]=> string(3) "bef" }

Convert your array as following numbers array and run the code
$numbers = array(
array("a", "b"),
array("c", "d", "e"),
array("f"),
);
$f_nb = $numbers['0'];
$s_nb = $numbers['1'];
$t_nb = $numbers['2'];
$final_array = array();
for($a = 0; $a<sizeof($f_nb); $a++)
{
for($b = 0; $b<sizeof($s_nb); $b++)
{
for($c = 0; $c<sizeof($t_nb); $c++)
{
$final_array[] = $f_nb["$a"] . $s_nb["$b"] . $t_nb["$c"];
}
}
}
print_r($final_array);

Try this:
$array = array(
'0' => array(
'0' => array('a'),
'1' => array('b')
),
'1' => array(
'0' => array('c'),
'1' => array('d'),
'2' => array('e')
),
'2' => array(
'0' => array('f')
),
);
$outcome = array();
foreach ($array['0'] as $key => $value1)
{
foreach ($array['1'] as $value2)
{
foreach ($array['2'] as $value3)
{
$outcome[] = $value1[0].$value2[0].$value3[0];
}
}
}
print_r($outcome);

Related

Comparing 2 Arrays using array_map?

I wanted to refrain from using nested foreach in my actual code, so I was thinking of using an array function (correct me if I'm wrong) called array_walk thinking it would replace my code in foreach.
I wanted to compare both of the WHOLE array if they one of them have the same description, but the problem is array_walk only compares the first key/index and does not go through the second index to check. is there other way? I'm just trying to optimize my code
By the way, this code returns both found
<?php $array = array (
'1' => array(
'count' => '1',
'id' => 1,
'description' => 'Bag',
),
'2' => array(
'count' => '1',
'id' => 2,
'description' => 'Pencil',
), );
$bin = array (
'1' => array(
'count' => '1',
'id' => 2,
'description' => 'Bag',
),
'2' => array(
'count' => '1',
'id' => 2,
'description' => 'Pencil',
), );
$b = array_map(function($array, $bin) {
if ($array['description'] == $bin['description']){
$count = "found";
}else{
$count = "not found";
}
return array("status" => $count, "cart_array" => $array['description'], "bin"=>$bin['description']); }, $array, $bin);
var_dump($b);
?>
but this one, the first array doesnt return found, it should return
found because there is a pencil and bag in $bin array updated the code
<?php
$array = array (
'1' => array(
'count' => '1',
'id' => 1,
'description' => 'Bag',
),
'2' => array(
'count' => '1',
'id' => 2,
'description' => 'Pencil',
),
);
$bin = array (
'1' => array(
'count' => '1',
'id' => 2,
'description' => 'Pencil',
),
'2' => array(
'count' => '1',
'id' => 2,
'description' => 'Bag',
),
);
$b = array_map(function($array, $bin)
{
if ($array['description'] == $bin['description']){
$count = "found";
}else{
$count = "not found";
}
return array("status" => $count, "cart_array" => $array['description'], "bin"=>$bin['description']);
}, $array, $bin);
var_dump($b);
?>
Use array_column first to get all of description keys from $array. Then, you can check these values with $bin values.
$desc = array_column($array, 'description');
$b = array_map(function($array, $bin)
{
global $desc;
if (in_array($bin['description'], $desc)){
$count = "found";
}else{
$count = "not found";
}
return array("status" => $count, "cart_array" => $array['description'], "bin" => $bin['description']);
}, $array, $bin);
var_dump($b);
You don't have any expected output in the question but I assume you want to know the difference between them.
In the manual for array_diff there is a code called arrayRecursiveDiff which handles multidimensional arrays and outputs the difference.
var_dump(arrayRecursiveDiff($array, $bin));
function arrayRecursiveDiff($aArray1, $aArray2) {
$aReturn = array();
foreach ($aArray1 as $mKey => $mValue) {
if (array_key_exists($mKey, $aArray2)) {
if (is_array($mValue)) {
$aRecursiveDiff = arrayRecursiveDiff($mValue, $aArray2[$mKey]);
if (count($aRecursiveDiff)) { $aReturn[$mKey] = $aRecursiveDiff; }
} else {
if ($mValue != $aArray2[$mKey]) {
$aReturn[$mKey] = $mValue;
}
}
} else {
$aReturn[$mKey] = $mValue;
}
}
return $aReturn;
}
This outputs:
array(2) {
[1]=>
array(2) {
["id"]=>
int(1)
["description"]=>
string(3) "Bag"
}
[2]=>
array(1) {
["description"]=>
string(6) "Pencil"
}
}
You can use this.Nevertheless both arrays have different length or the values do not have the same position, This will work :
$bin_desc=array_column($bin,'description');
$b = array_map(function($array)use($bin_desc) {
if (in_array($array['description'],$bin_desc)){
$count = "found";
}else{
$count = "not found";
}
return array("status" => $count, "cart_array" => $array['description'], "bin"=>$array['description']); }, $array);
var_dump($b);

How to convert flat PHP array to indexed array

I have the following array:
'values' => [
'protein_question_0_typing_method' => '38'
'protein_question_0_amount_1' => '1'
'protein_question_0_amount_2' => '2'
'protein_question_0_units_of_measurement' => '17'
'protein_question_1_typing_method' => '39'
'protein_question_1_amount_1' => '2'
'protein_question_1_amount_2' => '2'
'protein_question_1_units_of_measurement' => '17'
'protein_question_2_typing_method' => '42'
'protein_question_2_amount_1' => '2'
'protein_question_2_amount_2' => '2'
'protein_question_2_units_of_measurement' => '17'
'distributionId' => '21'
]
How would I convert into a structure like this?
'values' => [
0 => [
'protein_question_typing_method' => '38',
'protein_question_amount_1' => '1',
'protein_question_amount_2' => '2'
],
1 => [
'protein_question_typing_method' => '42',
'protein_question_amount_1' => '1',
'protein_question_amount_2' => '2'
],
...
'distributionId' => '21'
]
This is what I've tried:
$params = \Yii::$app->request->post();
$length = count($params['values']);
for($i = 0; $i < $length; $i++) {
if(!empty($params['values']['protein_question_' . $i . '_typing_method'])) {
echo $params['values']['protein_question_' . $i . '_typing_method'] . "<br /><hr />";
}
}
The above code just prints the data, the reason I need it in the chunked format is because each chunk will be saved as a new model record in the DB.
So basically just need to convert it to an index array, anyone know the easiest way to do this as looping over the first array would be complicated?
Thanks
Can do
$input = [
'values' => [
'protein_question_0_typing_method' => '38',
'protein_question_0_amount_1' => '1',
'protein_question_0_amount_2' => '2',
'protein_question_0_units_of_measurement' => '17',
'protein_question_1_typing_method' => '39',
'protein_question_1_amount_1' => '2',
'protein_question_1_amount_2' => '2',
'protein_question_1_units_of_measurement' => '17',
'protein_question_2_typing_method' => '42',
'protein_question_2_amount_1' => '2',
'protein_question_2_amount_2' => '2',
'protein_question_2_units_of_measurement' => '17',
'distributionId' => '21'
]
];
$output = [];
foreach ($input["values"] as $key => $value) {
if (preg_match('#^protein_question_(\d+)_(.+)$#', $key, $match)) {
$output[$match[1]]['protein_question_' . $match[2]] = $value;
} else {
$output[$key] = $value;
}
}
var_dump($output);
This will iterate over all the keys in the array and match if the start with protein_question, followed by a number, followed by some text. If so, the number is used as the index in the output to hold the key minus the number along with the value. If it doesnt match, the key and value are put as is.
Will give
array(4) {
[0]=>
array(4) {
["protein_question_typing_method"]=>
string(2) "38"
["protein_question_amount_1"]=>
string(1) "1"
["protein_question_amount_2"]=>
string(1) "2"
["protein_question_units_of_measurement"]=>
string(2) "17"
}
[1]=>
array(4) {
["protein_question_typing_method"]=>
string(2) "39"
["protein_question_amount_1"]=>
string(1) "2"
["protein_question_amount_2"]=>
string(1) "2"
["protein_question_units_of_measurement"]=>
string(2) "17"
}
[2]=>
array(4) {
["protein_question_typing_method"]=>
string(2) "42"
["protein_question_amount_1"]=>
string(1) "2"
["protein_question_amount_2"]=>
string(1) "2"
["protein_question_units_of_measurement"]=>
string(2) "17"
}
["distributionId"]=>
string(2) "21"
}
Here a very basic implementation to get you started, you may want to adjust it to your specific needs:
<?php
$values = [
'protein_question_0_typing_method' => '38',
'protein_question_0_amount_1' => '1',
'protein_question_0_amount_2' => '2',
'protein_question_0_units_of_measurement' => '17',
'protein_question_1_typing_method' => '39',
'protein_question_1_amount_1' => '2',
'protein_question_1_amount_2' => '2',
'protein_question_1_units_of_measurement' => '17',
'protein_question_2_typing_method' => '42',
'protein_question_2_amount_1' => '2',
'protein_question_2_amount_2' => '2',
'protein_question_2_units_of_measurement' => '17',
'distributionId' => '21'
];
function convert($values) {
$result = [];
foreach ($values as $key => $value) {
$matches = [];
$ret = preg_match('~^protein_question_([0-9]+)_~U', $key, $matches);
// Key does not match the pattern protein_question_*_
if ($ret !== 1) {
$result[$key] = $value;
continue;
}
$proteinQuestionID = (int)$matches[1];
// Create key for the this ID
if (!isset($result[$proteinQuestionID])) {
$result[$proteinQuestionID] = [];
}
// Adjust the key...
$key = \substr($key, \strlen('protein_question_'.$proteinQuestionID));
$key = 'protein_question'.$key;
// Append to it...
$result[$proteinQuestionID][$key] = $value;
}
return $result;
}
print_r(convert($values));
did you tried array_chunk($your_array, 4) . it looks this method can help you

PHP multidimensional array key collapse

I'd like to collapse a multidimensional array so that
$arr = array(
'first' => array(
'second' => array(
0 => 'foo',
1 => 'bar'
)
)
);
would collapse to
$arr = array(
'first[second][0]' => 'foo',
'first[second][1]' => 'bar'
);
What I'm trying to do is to restore a multipart/form-data $_POST array to the original request body, like this:
------WebKitFormBoundaryxiOccKlMg4Al6VbH
Content-Disposition: form-data; name="first[second][0]"
foo
------WebKitFormBoundaryxiOccKlMg4Al6VbH
Content-Disposition: form-data; name="first[second][1]"
bar
------WebKitFormBoundaryxiOccKlMg4Al6VbH--
Try this code:
$arr = array(
'first' => array(
'second' => array(
0 => 'foo',
1 => 'bar'
)
)
);
$result = array();
function processLevel(&$result, $source, $previous_key = null) {
foreach ($source as $k => $value) {
$key = $previous_key ? "{$previous_key}[{$k}]" : $k;
if (!is_array($value)) {
$result[$key] = $value;
} else {
processLevel($result, $value, $key);
}
}
}
processLevel($result, $arr);
var_dump($result);
die();
It outputs:
array(2) {
["first[second][0]"] => string(3) "foo"
["first[second][1]"] => string(3) "bar"
}
what about this?
$arr = array(
'first' => array(
'second' => array(
0 => 'foo',
1 => 'bar'
)
)
);
$newArray=array();
foreach($arr['first']['second'] as $k=>$v)
{
$newArray['first[second]['.$k.']']=$v;
}
var_dump($arr);
var_dump($newArray);
I hope this helps.
function collapseArray ($array, $tree = array(), $step = 0) {
$result = array();
foreach ($array as $key => $val) {
$tree[$step] = $key;
if (is_scalar($val)) {
$first = array_shift($tree);
$result["{$first}[".implode("][", $tree)."]"] = $val;
array_unshift($tree, $first);
} else {
$result += collapseArray($val, $tree, $step + 1);
}
}
return $result;
}
$arr = array(
'first' => array(
'second' => array(
0 => 'foo',
1 => 'bar'
)
)
);
$newArray = collapseArray($arr);
Outputs when var_dump()'ed:
array(2) {
["first[second][0]"]=>
string(3) "foo"
["first[second][1]"]=>
string(3) "bar"
}

PHP: Building multidimensional array

I have an array like this:
Array(
'level1' => 'someval',
'level2' => 'someotherval',
'level3' => 'thirdval'
)
I want to turn it into this:
Array(
'someval' => Array(
'someotherval' => Array(
'thirdval' => 1
)
)
)
Obviously I could build the example above by hand but I don't know how many levels there will be. And this simple example might seem useless, but there are going to be more values, so there will be multiple arrays inside each of the levels.
This will do it
$array = array(
'level1' => array(
'level2' => array(
'level3' => 1
)
)
);
Here's my take on it:
function make_multi_level_array($arr) {
if (count($arr) == 1) return array(array_pop($arr) => 1);
else {
$level_key = array_pop(array_reverse($arr));
$sub_level = make_multi_level_array(
array_slice($arr,1,count($arr)-1)
);
return array(
$level_key => $sub_level
);
}
}
$arr = array(
'level1' => 'someval',
'level2' => 'someotherval',
'level3' => 'thirdval',
);
var_dump(make_multi_level_array($arr));
Will output this:
array(1) {
["someval"]=>
array(1) {
["someotherval"]=>
array(1) {
["thirdval"]=>
int(1)
}
}
}
Also tried other cases like below.
$arr = array(
'level1' => 'someval',
'level2' => 'someotherval',
'level3' => 'thirdval',
'level4' => 'fourthval'
);
Seems okay:
array(1) {
["someval"]=>
array(1) {
["someotherval"]=>
array(1) {
["thirdval"]=>
array(1) {
["fourthval"]=>
int(1)
}
}
}
}
Do you need something like this?
$levels = array_keys(Array(
'level1' => 'someval',
'level2' => 'someotherval',
'level3' => 'thirdval'
));
$array = Array();
$aux = &$array;
foreach ($levels as $level => $value) {
if ($aux == 1)
$aux = array($value => 1);
$aux = &$aux[$value];
}
var_dump($array);

recursive function php

I have an array which looks like this
$dataArray = array (
0 =>
array (
'UserId' => '804023',
'ProjectCode' => 'RA1234',
'Role' => 'PI',
),
1 =>
array (
'UserId' => '804023',
'ProjectCode' => 'RA1234',
'Role' => 'PM',
),
2 =>
array (
'UserId' => '804023',
'ProjectCode' => 'A90123',
'Role' => 'CI',
),
3 =>
array (
'UserId' => '804023',
'ProjectCode' => 'A20022',
'Role' => 'PM',
),
)
I need it to look like this
$expected = array (
804023 =>
array (
'RA1234' =>
array (
0 => 'PI',
1 => 'PM',
),
'A90123' =>
array (
0 => 'PI',
),
'A20022' =>
array (
0 => 'CI',
),
),
)
I think this could be achieved generically using recursion as this is a scenario I am likely to come across many times
I have got this far passing in an array of keys that form the nested array keys i.e.
$keys=array("UserId","projectCode","Role");
but am just not seeing where to go from here any pointers?
public function structureData(array $data, array $keys)
{
//$structuredData = array();
foreach ($data as $key => $value)
{
$keyForData = array_slice($keys,0,1);
$remainingKeys = $keys;
array_shift($remainingKeys);
if (!array_key_exists($value[$keyForData[0]], $structuredData))
{
$count=count($remainingKeys);
$structuredData[$value[$keyForData[0]]] =array();
// this returns as expected array(804023 =>array ()); but subsequent recursive calls with the remaining data fail
}
}
return $structuredData);
}
You don't need recursion, just a loop:
foreach ($dataArray as $da) {
$expected[$da['UserId']][$da['ProjectCode']][] = $da['Role'];
}
var_export($expected);
/* output:
array (
804023 =>
array (
'RA1234' =>
array (
0 => 'PI',
1 => 'PM',
),
'A90123' =>
array (
0 => 'CI',
),
'A20022' =>
array (
0 => 'PM',
),
),
)
*/
A crude but functioning solution.
function structureData($data, $keys){
$out = array();
foreach($data as $row){
$subout = &$out;
foreach(array_slice($keys, 0, -1) as $key){
$value = $row[$key];
$subout = &$subout[$value];
}
$subout[] = $row[$keys[count($keys) - 1]];
}
return $out;
}
print_r(structureData($dataArray, array('UserId', 'ProjectCode', 'Role')));
Recursion? Nah. Try this:
function add_role($dataArray, $userid, $project_code, $role)
{
$dataArray[$userid][$project_code][] = $role;
}
Functional solution:
$t = array_gather_key($dataArray, function ($e) { return $e['UserId']; } );
$t = array_map(
function ($e) {
return array_gather_key($e,
function ($e) { return $e['ProjectCode']; },
function ($e) { return $e['Role']; } );
},
$t
);
With this higher-order function:
function array_gather_key($array, $func, $transf = null) {
$res = array();
foreach ($array as $elem) {
$key = $func($elem);
if (!array_key_exists($key, $res))
$res[$key] = array();
if ($transf === null)
$res[$key][] = $elem;
else
$res[$key][] = $transf($elem);
}
return $res;
}
This gives:
array(1) {
[804023]=>
array(3) {
["RA1234"]=>
array(2) {
[0]=>
string(2) "PI"
[1]=>
string(2) "PM"
}
["A90123"]=>
array(1) {
[0]=>
string(2) "CI"
}
["A20022"]=>
array(1) {
[0]=>
string(2) "PM"
}
}
}

Categories