PHP multidimensional array key collapse - php

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

Related

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

Convert array keys to a string in PHP

Example Array:
$array = array([key1] =>
array([key11] =>
array([key111] => 'value111',
[key112] => 'value112',
[key113] => 'value113',
[key114] => array(A,B,C,D),
),
),
);
I need an output as below array:
array([key1/key11/key111] => 'value111',
[key1/key11/key112] => 'value112',
[key1/key11/key113] => 'value113',
[key1/key11/key114] => 'A,B,C,D' );
and i have tried using this function,
function listArrayRecursive($someArray, &$outputArray, $separator = "/") {
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($someArray), RecursiveIteratorIterator::SELF_FIRST);
foreach ($iterator as $k => $v) {
if (!$iterator->hasChildren()) {
for ($p = array(), $i = 0, $z = $iterator->getDepth(); $i <= $z; $i++) {
$p[] = $iterator->getSubIterator($i)->key();
}
$path = implode($separator, $p);
$outputArray[] = $path;
}
}
}
$outputArray = array();
listArrayRecursive($array, $outputArray);
I cant able to find how to achieve this by using the above function for "key1/key11/key114" getting value as i expected. Please help me on this.
Input:
$array = array(
'key1' => array(
'key11' => array(
'key111' => 'value111',
'key112' => 'value112',
'key113' => 'value113',
'key114' => array('A','B','C','D'),
),
'key12' => array(
'key121' => 'value121',
'key122' => 'value122',
'key123' => 'value123',
'key124' => array('A','B','C','D'),
),
),
'key2' => array(
'key21' => array(
'key211' => 'value111',
'key212' => 'value112',
'key213' => 'value113',
'key214' => array('A','B','C','D'),
),
),
);
Script:
function remap_keys($input, $max_depth, $separator = '/', /* reserved */ $keychain = array(), /* reserved */ &$output = array())
{
foreach ($input as $key => $element)
{
$element_keychain = array_merge($keychain, (array)$key);
if (($max_depth > 1) && is_array($element))
remap_keys($element, $max_depth -1, $separator, $element_keychain, $output);
else
$output[implode($separator, $element_keychain)] = implode(',', (array)$element);
}
return $output;
}
$array = remap_keys($array, 3);
print_r($array);
Output:
Array
(
[key1/key11/key111] => value111
[key1/key11/key112] => value112
[key1/key11/key113] => value113
[key1/key11/key114] => A,B,C,D
[key1/key12/key121] => value121
[key1/key12/key122] => value122
[key1/key12/key123] => value123
[key1/key12/key124] => A,B,C,D
[key2/key21/key211] => value111
[key2/key21/key212] => value112
[key2/key21/key213] => value113
[key2/key21/key214] => A,B,C,D
)
http://ideone.com/pqH45h
$array = array('key1' =>
array('key11' =>
array('key111' => 'value111',
'key112' => 'value112',
'key113' => 'value113',
'key114' => array(A,B,C,D),
),
),
);
function implode_arr_keys($array, $output_arr = array(), $cur_key = FALSE) {
foreach($array as $key => $value) {
if(is_array($value)) {
return implode_arr_keys($value, $output_arr, ($cur_key == FALSE ? $key : $cur_key.'/'.$key));
} else {
if(!is_numeric($key))
$output_arr[$cur_key.'/'.$key] = $value;
else
$output_arr[$cur_key] = $array;
}
}
return $output_arr;
}
print_r($array);
print_r(implode_arr_keys($array));

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

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

PHP Recursively unset array keys if match

I have the following array that I need to recursively loop through and remove any child arrays that have the key 'fields'. I have tried array filter but I am having trouble getting any of it to work.
$myarray = array(
'Item' => array(
'fields' => array('id', 'name'),
'Part' => array(
'fields' => array('part_number', 'part_name')
)
),
'Owner' => array(
'fields' => array('id', 'name', 'active'),
'Company' => array(
'fields' => array('id', 'name',),
'Locations' => array(
'fields' => array('id', 'name', 'address', 'zip'),
'State' => array(
'fields' => array('id', 'name')
)
)
)
)
);
This is how I need it the result to look like:
$myarray = array(
'Item' => array(
'Part' => array(
)
),
'Owner' => array(
'Company' => array(
'Locations' => array(
'State' => array(
)
)
)
)
);
If you want to operate recursively, you need to pass the array as a reference, otherwise you do a lot of unnecessarily copying:
function recursive_unset(&$array, $unwanted_key) {
unset($array[$unwanted_key]);
foreach ($array as &$value) {
if (is_array($value)) {
recursive_unset($value, $unwanted_key);
}
}
}
you want array_walk
function remove_key(&$a) {
if(is_array($a)) {
unset($a['fields']);
array_walk($a, __FUNCTION__);
}
}
remove_key($myarray);
My suggestion:
function removeKey(&$array, $key)
{
if (is_array($array))
{
if (isset($array[$key]))
{
unset($array[$key]);
}
if (count($array) > 0)
{
foreach ($array as $k => $arr)
{
removeKey($array[$k], $key);
}
}
}
}
removeKey($myarray, 'Part');
function recursive_unset(&$array, $unwanted_key) {
if (!is_array($array) || empty($unwanted_key))
return false;
unset($array[$unwanted_key]);
foreach ($array as &$value) {
if (is_array($value)) {
recursive_unset($value, $unwanted_key);
}
}
}
function sanitize($arr) {
if (is_array($arr)) {
$out = array();
foreach ($arr as $key => $val) {
if ($key != 'fields') {
$out[$key] = sanitize($val);
}
}
} else {
return $arr;
}
return $out;
}
$myarray = sanitize($myarray);
Result:
array (
'Item' =>
array (
'Part' =>
array (
),
),
'Owner' =>
array (
'Company' =>
array (
'Locations' =>
array (
'State' =>
array (
),
),
),
),
)
function removeRecursive($haystack,$needle){
if(is_array($haystack)) {
unset($haystack[$needle]);
foreach ($haystack as $k=>$value) {
$haystack[$k] = removeRecursive($value,$needle);
}
}
return $haystack;
}
$new = removeRecursive($old,'key');
Code:
$sweet = array('a' => 'apple', 'b' => 'banana');
$fruits = array('sweet' => $sweet, 'sour' => $sweet);
function recursive_array_except(&$array, $except)
{
foreach($array as $key => $value){
if(in_array($key, $except, true)){
unset($array[$key]);
}else{
if(is_array($value)){
recursive_array_except($array[$key], $except);
}
}
}
return;
}
recursive_array_except($fruits, array('a'));
print_r($fruits);
Input:
Array
(
[sweet] => Array
(
[a] => apple
[b] => banana
)
[sour] => Array
(
[a] => apple
[b] => banana
)
)
Output:
Array
(
[sweet] => Array
(
[b] => banana
)
[sour] => Array
(
[b] => banana
)
)
I come up with a simple function that you can use to delete multiple array element based on multiple keys.
Detail example here.
Just a little change in code.
function removeRecursive($inputArray,$delKey){
if(is_array($inputArray)){
$moreKey = explode(",",$delKey);
foreach($moreKey as $nKey){
unset($inputArray[$nKey]);
foreach($inputArray as $k=>$value) {
$inputArray[$k] = removeRecursive($value,$nKey);
}
}
}
return $inputArray;
}
$inputNew = removeRecursive($input,'keyOne,keyTwo');
print"<pre>";
print_r($inputNew);
print"</pre>";
Give this function a shot. It will remove the keys with 'fields' and leave the rest of the array.
function unsetFields($myarray) {
if (isset($myarray['fields']))
unset($myarray['fields']);
foreach ($myarray as $key => $value)
$myarray[$key] = unsetFields($value);
return $myarray;
}
Recursively walk the array (by reference) and unset the relevant keys.
clear_fields($myarray);
print_r($myarray);
function clear_fields(&$parent) {
unset($parent['fields']);
foreach ($parent as $k => &$v) {
if (is_array($v)) {
clear_fields($v);
}
}
}
I needed to have a little more granularity in unsetting arrays and I came up with this - with the evil eval and other dirty tricks.
$post = array(); //some huge array
function array_unset(&$arr,$path){
$str = 'unset($arr[\''.implode('\'][\'',explode('/', $path)).'\']);';
eval($str);
}
$junk = array();
$junk[] = 'property_meta/_edit_lock';
$junk[] = 'property_terms/post_tag';
$junk[] = 'property_terms/property-type/0/term_id';
foreach($junk as $path){
array_unset($post,$path);
}
// unset($arr['property_meta']['_edit_lock']);
// unset($arr['property_terms']['post_tag']);
// unset($arr['property_terms']['property-type']['0']['term_id']);

Categories