PHP: Building multidimensional array - php

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);

Related

Adding another dimension to array

I have an array of TLDs and prices, and now I want to be able to add a classification i.e. 'Australian','New Zealand','Industry' to the domains but I am having troubles adding the extra dimension.
The array I have is
$domains = array(
'.com.au' => '19.98',
'.melbourne' => '90.00',
'.academy' => '45.00',
'.accountants' => '120.00',
'.ac.nz' => '36.75');
$domains = array(
'.com.au' => array(
'country' => 'Australia',
'sector' => 'Industry',
'price' => '19.98'
),
);
Is this a beginning on what you're looking for ?
Is this code ok for you?
<?php
$domains = array(
'.com.au' => '19.98',
'.melbourne' => '90.00',
'.academy' => '45.00',
'.accountants' => '120.00',
'.ac.nz' => '36.75');
$newDomains = [];
foreach($domains as $key=>$value){
if($key == '.com.au'){
$newDomains[$key]['TLD'] = $value;
$newDomains[$key]['Industry'] = 'blabal';
}else{
$newDomains[$key] = $value;
}
}
echo '<pre>';
var_dump($newDomains);
echo '</pre>';
?>
Or even:
$domains = array(
'.com.au' => '19.98',
'.melbourne' => '90.00',
'.academy' => '45.00',
'.accountants' => '120.00',
'.ac.nz' => '36.75');
$industryArray = array(
'.com.au' => 'blabla'
);
$newDomains = [];
foreach($domains as $key=>$value){
if(isset($industryArray[$key])){
$newDomains[$key]['TLD'] = $value;
$newDomains[$key]['Industry'] = $industryArray[$key];
}else{
$newDomains[$key] = $value;
}
}
echo '<pre>';
var_dump($newDomains);
echo '</pre>';
The result is:
array(5) {
[".com.au"]=>
array(2) {
["TLD"]=>
string(5) "19.98"
["Industry"]=>
string(6) "blabla"
}
[".melbourne"]=>
string(5) "90.00"
[".academy"]=>
string(5) "45.00"
[".accountants"]=>
string(6) "120.00"
[".ac.nz"]=>
string(5) "36.75"
}

Combine array elements

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);

Replace values with their keys in multidimensional array

I need to replace all values in a multidimensional array by their respective key, but only if the value is not an array.
From:
array(
'key1' => array(
'key2' => array(
'key3' => 'val'
)
)
);
To:
array(
'key1' => array(
'key2' => array(
'key3'
)
)
);
Does anyone know a way to do this nicely?
This seems to do more or less what you want (fiddle):
<?php
function convert($arr) {
$ret = array();
foreach ($arr as $key => $value) {
if (is_array($value)) {
$ret[$key] = convert($value);
} else {
$ret[] = $key;
}
}
return $ret;
}
$test = array(
'key1' => array(
'key2' => array(
'key3' => 'val'
)
)
);
var_dump(convert($test));
Output:
array(1) {
["key1"]=>
array(1) {
["key2"]=>
array(1) {
[0]=>
string(4) "key3"
}
}
}

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"
}

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