Transform a monodimensional PHP array into a multidimensional one - php

How would you transform a monodimensional array into a multidimensional array in PHP? Suppose you have something like this
$array['breakfast'] = 'milk';
$array['meal.firstdish'] = 'pasta';
$array['meal.seconddish.maincourse'] = 'veal';
$array['meal.seconddish.dressing'] = 'fries';
$array['meal.dessert'] = 'pie';
And you want a function to transform it into
$array['breakfast'] = 'milk';
$array['meal']['firstdish'] = 'pasta';
$array['meal']['seconddish']['maincourse'] = 'veal';
$array['meal']['seconddish']['dressing'] = 'fries';
$array['meal']['dessert'] = 'pie';
The same function should of course transform
$tire['ean'] = '3286347717116';
$tire['brand.maker'] = 'BRIDGESTONE';
$tire['brand.model.name'] = 'POTENZA';
$tire['brand.model.variant'] = 'RE 040 RFT * SZ';
into
$tire['ean'] = '3286347717116';
$tire['brand']['maker'] = 'BRIDGESTONE';
$tire['brand']['model']['name'] = 'POTENZA';
$tire['brand']['model']['variant'] = 'RE 040 RFT * SZ';
I was thinking of using explode, then eval on the results, but eval always feels like cheating to me and I guess it would keep my code from running in HipHop.
The reason I want to do this is that I have to export lots of different tables from a database into XML files, and I already have a robust function that turns a multidimensional array into XML.

Like this:
function build(array &$trg, array $k,$key,$value) {
$p = &$trg;
while ( !empty($k) ) {
$nk = array_shift($k);
if ( !isset($p[$nk]) ) {
$p[$nk] = [];
}
$p = &$p[$nk];
}
$p[$key] = $value;
return $p;
}
$array['breakfast'] = 'milk';
$array['meal.firstdish'] = 'pasta';
$array['meal.seconddish.maincourse'] = 'veal';
$array['meal.seconddish.dressing'] = 'fries';
$array['meal.dessert'] = 'pie';
$out = [];
foreach ($array as $key => $value ) {
$path = explode('.',$key);
$last = array_pop($path);
build($out,$path,$last,$value);
}
print_r($out);

You were on the right track with explode, but there's no need to use eval. Once you've got the pieces of the keys available, you can loop over them and incrementally assign a pointer into a new array:
<?php
$array['breakfast'] = 'milk';
$array['meal.firstdish'] = 'pasta';
$array['meal.seconddish.maincourse'] = 'veal';
$array['meal.seconddish.dressing'] = 'fries';
$array['meal.dessert'] = 'pie';
$result = [];
$target = null;
foreach ($array as $key => $value) {
// Start by targeting the base of our resulting array
$target =& $result;
// Break the keys apart into pieces
$keyParts = explode('.', $key);
// Assign new target based on indexing into the result array one "piece" at a time
while ($part = array_shift($keyParts)) {
$target =& $target[$part];
}
// Finally, assign the value to our target
$target = $value;
}
See https://eval.in/625627

Related

How to dynamically traverse a global array without creating any copy of it?

What happen if it is a very big array? One would try to save memory. The next example makes copies of parts of the array, but it should be not necessary, since the array is a global variable.
function arrayTraverse($key) {
global $someArray;
$keys = func_get_args();
$arrayPart = $someArray;
foreach ($keys as $key) {
$arrayPart = $arrayCopy[$key];
}
$value = $arrayPart;
return $value;
}
Usage example:
$someArray = [];
$someArray['aKey'] = [];
$someArray['aKey']['someOtherKey'] = [];
$someArray['aKey']['someOtherKey'][5] = [];
$someArray['aKey']['someOtherKey'][5]['value'] = 'hello';
echo arrayTraverse('aKey', 'someOtherKey', 5, 'value'); // hello

How to reference cells with specific condition in php multidimensional array

I got an array like this:
$array[0][name] = "Axel";
$array[0][car] = "Pratzner";
$array[0][color] = "black";
$array[1][name] = "John";
$array[1][car] = "BMW";
$array[1][color] = "black";
$array[2][name] = "Peggy";
$array[2][car] = "VW";
$array[2][color] = "white";
I would like to do something like "get all names WHERE car = bmw AND color = white"
Could anyone give advice on how the PHP spell would look like?
function getWhiteBMWs($array) {
$result = array();
foreach ($array as $entry) {
if ($entry['car'] == 'bmw' && $entry['color'] == 'white')
$result[] = $entry;
}
return $result;
}
Edited: This is a more general solution:
// Filter an array using the given filter array
function multiFilter($array, $filters) {
$result = $array;
// Removes entries that don't pass the filter
$fn = function($entry, $index, $filter) {
$key = $filter['key'];
$value = $filter['value'];
$result = &$filter['array'];
if ($entry[$key] != $value)
unset($result[$index]);
};
foreach ($filters as $key => $value) {
// Pack the filter data to be passed into array_walk
$filter = array('key' => $key, 'value' => $value, 'array' => &$result);
// For every entry, run the function $fn and pass in the filter data
array_walk($result, $fn, $filter);
}
return array_values($result);
}
// Build a filter array - an entry passes this filter if every
// key in this array corresponds to the same value in the entry.
$filter = array('car' => 'BMW', 'color' => 'white');
// multiFilter searches $array, returning a result array that contains
// only the entries that pass the filter. In this case, only entries
// where $entry['car'] = 'BMW' AND $entry['color'] = 'white' will be
// returned.
$whiteBMWs = multiFilter($array, $filter);
Doing this in code is more or less emulating what a RDBMS is perfect for. Something like this would work:
function getNamesByCarAndColor($array,$color,$car) {
$matches = array();
foreach ($array as $entry) {
if($entry["color"]== $color && $entry["car"]==$car)
matches[] = $entry["name"];
}
return $matches;
}
This code would work well for smaller arrays, but as they got larger and larger it would be obvious that this isn't a great solution and an indexed solution would be much cleaner.

Merge complex array php

I have a site developed in php (codeigniter) and I want to merge some array with same structure.
This is the constructor of my array:
$first = array();
$first['hotel'] = array();
$first['room'] = array();
$first['amenities'] = array();
/*
Insert data into $first array
*/
$second = array();
$second['hotel'] = array();
$second['room'] = array();
$second['amenities'] = array();
/*
Insert data into $second array
*/
After insert data I want to merge this array but the problem is that I have subarray inside it and I want to create a unique array like that:
$total = array();
$total['hotel'] = array();
$total['room'] = array();
$total['amenities'] = array();
This is the try to merge:
$total = array_merge((array)$first, (array)$second);
In this array I have only the $second array why?
Use the recursive version of array_merge called array_merge_recursive.
It seems like array_merge doesn't do what you think it does: "If the input arrays have the same string keys, then the later value for that key will overwrite the previous one." Try this:
function merge_subarrays ($first, $second)
$result = array();
foreach (array_keys($first) as $key) {
$result[$key] = array_merge($first[$key], $second[$key]);
};
return $result;
};
Then call it as:
$total = merge_subarrays($first, $second);
and, if I've correctly understood your question, $total will contain the result you're looking for.
There is no standard way of doing it, you just have to do something like:
<?php
$first = array();
$first['hotel'] = array('hello');
$first['room'] = array();
$first['amenities'] = array();
/*
Insert data into $first array
*/
$second = array();
$second['hotel'] = array('world');
$second['room'] = array();
$second['amenities'] = array();
$merged = array();
foreach( $first as $key => $value )
{
$merged[$key] = array_merge( $value, $second[$key] );
}
print_r( $merged );

PHP string to nested array

I need to convert a string from an ldap query. I am querying my Active Directory server for user accounts. This is the string that I pulled.
"CN=Phil Robertson,OU=Users,OU=Duck Commander,OU=Department & Buildings,DC=OCSDtest,DC=local"
I would want it converted to an array that looks like this
$array['local']['OCtest']['Department & Buildings']['Duck Commander']['Users']['Phil Robertson']=1;
NOT
$array( [1]=>'local,[2]=>'OCtest',[3]='Depart',[4]='Duck Commander',[5]='Users');
So far I have
Example code ---
$dnn2 = ldap_explode_dn("CN=Phil Robertson,OU=Users,OU=Duck Commander,OU=Department & Buildings,DC=OCSDtest,DC=local",1);
unset($dnn2['count']);
echo "<pre>";
print_r(array_reverse($dnn2));
What am I needing?
Try this
$arrayvalue = array();
foreach($dnn2 as $dn)
{
$temp = explode('=',$dn);
$temp1 = substr($temp[1], 0, strpos($temp1[1], ','));
$arrayvalue[] = $temp1;
}
print_r($arrayvalue);
$dnn2 = ldap_explode_dn("CN=Phil Robertson,OU=Users,OU=Duck Commander,OU=Department & Buildings,DC=OCSDtest,DC=local",1);
unset($dnn2['count']);
$result = null;
$ref =& $result;
foreach (array_reverse($dnn2) as $dn) {
$ref = array($dn => null);
$ref =& $ref[$dn];
}
print_r($result);
Try this
$a = array();
foreach($dnn2 as $dn)
{
$arr = explode('=',$dn);
$a[] = $arr[1]; //or $a[] = array($arr[1]); for 6 dimensional array
}
print_r($a);

Creating array from string

I need to create array like that:
Array('firstkey' => Array('secondkey' => Array('nkey' => ...)))
From this:
firstkey.secondkey.nkey.(...)
$yourString = 'firstkey.secondkey.nkey';
// split the string into pieces
$pieces = explode('.', $yourString);
$result = array();
// $current is a reference to the array in which new elements should be added
$current = &$result;
foreach($pieces as $key){
// add an empty array to the current array
$current[ $key ] = array();
// descend into the new array
$current = &$current[ $key ];
}
//$result contains the array you want
My take on this:
<?php
$theString = "var1.var2.var3.var4";
$theArray = explode(".", $theString); // explode the string into an array, split by "."
$result = array();
$current = &$result; // $current is a reference to the array we want to put a new key into, shifting further up the tree every time we add an array.
while ($key = array_shift($theArray)){ // array_shift() removes the first element of the array, and assigns it to $key. The loop will stop as soon as there are no more items in $theArray.
$current[$key] = array(); // add the new key => value pair
$current = &$current[$key]; // set the reference point to the newly created array.
}
var_dump($result);
?>
With an array_push() in the while loop.
What do you want the value of the deepest key to be?
Try something like:
function dotToArray() {
$result = array();
$keys = explode(".", $str);
while (count($keys) > 0) {
$current = array_pop($keys);
$result = array($current=>$result);
}
return $result;
}

Categories