I have multiple strings similar to:
$str = "/One/Two";
$str2 = "/One/Two/Flowers";
$str3 = "/One/Two/Grass";
$str4 = "/One/Another/Deeper";
$str5 = "/Uno/Dos/Cow";
I want to split it into a deep nested array that looks similar to the following:
Array
(
[One] => Array
(
[Two] => Array
(
[Flowers] =>
[Grass] =>
)
[Another] => Array
(
[Deeper] =>
)
)
[Uno] => Array
(
[Dos] => Array
(
[Cow] =>
)
)
)
This should do it:
$strings = array(
"/One/Two",
"/One/Two/Flowers",
"/One/Two/Grass",
"/One/Another/Deeper",
"/Uno/Dos/Cow"
);
$result = array();
foreach($strings as $string) {
$parts = array_filter(explode('/', $string));
$ref = &$result;
foreach($parts as $p) {
if(!isset($ref[$p])) {
$ref[$p] = array();
}
$ref = &$ref[$p];
}
$ref = null;
}
print_r($result);
Working example:
http://codepad.org/GmAoXLXp
Something like this should work. I couldn't think of any nice functional way to build the structure, so I fell back to a couple foreach loops.
<?php
$strings = array(
'/One/Two',
'/One/Two/Flowers',
'/One/Two/Grass',
'/One/Another/Deeper',
'/Uno/Dos/Cow'
);
$paths = array_map(
function ($e) {
return explode('/', trim($e, '/'));
},
$strings
);
$pathStructure = array();
foreach ($paths as $path) {
$ref =& $pathStructure;
foreach ($path as $dir) {
$ref =& $ref[$dir];
}
}
unset($ref);
print_r($pathStructure);
Related
This question already has answers here:
explode an array of delimited strings into two arrays
(6 answers)
Closed 9 months ago.
I have this $array DD.MM.YYYY|XX,xxx
[0]=> string(17) "04.01.2021|26,140"
[1]=> string(17) "05.01.2021|26,225"
[2]=> string(17) "06.01.2021|26,145"
I need to create 2 more arrays from it, e.g. $array_date and $array_value.
I tried something like foreach and inside the loop use explode() function but I have no idea, I also checked some previous posts for this problem but to no avail.
Try this way:
$data = [
'04.01.2021|26,140',
'05.01.2021|26,225',
'06.01.2021|26,145'
];
function extract_array($array) {
$result = [];
foreach($array as $row) {
$values = explode("|", $row);
$result['array_date'][] = $values[0];
$result['array_value'][] = $values[1];
}
return $result;
}
print_r(extract_array($data));
// Array
// (
// [array_date] => Array
// (
// [0] => 04.01.2021
// [1] => 05.01.2021
// [2] => 06.01.2021
// )
//
// [array_value] => Array
// (
// [0] => 26,140
// [1] => 26,225
// [2] => 26,145
// )
//
// )
As you described, you can use explode inside a foreach and then populate the 2 arrays.
Assuming the format of all the strings are the same:
$array = [
"04.01.2021|26,140",
"05.01.2021|26,225",
"06.01.2021|26,145"
];
$array_date = [];
$array_value = [];
foreach($array as $value) {
$parts = explode('|', $value);
$array_date[] = $parts[0];
$array_value[] = $parts[1];
}
This should work with list():
$array = [
"04.01.2021|26,140",
"05.01.2021|26,225",
"06.01.2021|26,145"
];
$date_array = [];
$value_array = [];
foreach ( $array as $i )
{
list($date, $value) = explode("|",$i);
$date_array[] = $date;
$value_array[] = $value;
}
You can also use array_walk_recursive()
I would prefer having dates and values as part of the same array when accessing them. Instead of $array_date[key] and $array_value[key] you would have them in $array[key]['date'] and $array[key]['value']. But it depends on what you want to do with the result.
$data = array(
"04.01.2021|26,140",
"05.01.2021|26,225",
"06.01.2021|26,145"
);
array_walk_recursive($data, function($value) use (&$result){
$parts = explode('|', $value);
$result[] = array(
'date' => $parts[0],
'value' => $parts[1]
);
});
print_r($result);
So I've got a list of paths, such as:
path/to/directory/file1
path/directory/file2
path2/dir/file3
path2/dir/file4
And I'd like to convert them into a multidimensional array like this:
array(
path => array(
to => array(
directory => array(
file1 => someValue
),
),
directory => array(
file2 => someValue
),
),
path2 => array(
dir => array(
file3 => someValue,
file4 => someValue
)
)
)
My first thought was to explode() the paths into segments and set up the array using a foreach loop, something like this:
$arr = array();
foreach ( $path as $p ) {
$segments = explode('/', $p);
$str = '';
foreach ( $segments as $s ) {
$str .= "[$s]";
}
$arr{$str} = $someValue;
}
But this doesn't work, and since the number of segments varies, I've kinda got stumped. Is there away to do this?
If somevalue can be an empty array:
<?php
$result = array();
$input = [
'path/to/directory/file1',
'path/directory/file2',
'path2/dir/file3',
'path2/dir/file4',
];
foreach( $input as $e ) {
nest( $result, explode('/', $e));
}
var_export($result);
function nest(array &$target, array $parts) {
if ( empty($parts) ) {
return;
}
else {
$e = array_shift($parts);
if ( !isset($target[$e]) ) {
$target[$e] = [];
}
nest($target[$e], $parts);
}
}
Here is the solution and a easy way
Just Reverse the whole exploded array and start creating array within a Array
$path[1] = "path/to/directory/file1";
$path[2] = "path/directory/file2";
$path[3] = "path2/dir/file3";
$path[4] = "path2/dir/file4";
$arr = array();
$b = array();
$k = 0;
foreach($path as $p) {
$c = 0;
$segments = explode('/', $p);
$reversed = array_reverse($segments);
foreach($reversed as $s) {
if ($c == 0) {
$g[$k] = array($s => "somevalue");
} else {
$g[$k] = array($s => $g[$k]);
}
$c++;
}
$k++;
}
var_dump($g);
Thanks so much VolkerK! Your answer didn't quite answer my question but it got me on the right track. Here's the version I ended up using to get it to work:
$result = array();
$input = [
'path/to/directory/file1' => 'someValue',
'path/directory/file2' => 'someValue',
'path2/dir/file3' => 'someValue',
'path2/dir/file4' => 'someValue',
];
foreach( $input as $e=>$val ) {
nest( $result, explode('/', $e), $val);
}
var_export($result);
function nest(array &$target, array $parts, $leafValue) {
$e = array_shift($parts);
if ( empty($parts) ) {
$target[$e] = $leafValue;
return;
}
if ( !isset($target[$e]) ) {
$target[$e] = [];
}
nest($target[$e], $parts, $leafValue);
}
I basically just added the somevalue as $leafValue and moved the base case around so that it would add the leafValue instead of a blank array at the end.
This results in:
Array
(
[path] => Array
(
[to] => Array
(
[directory] => Array
(
[file1] => someValue
)
)
[directory] => Array
(
[file2] => someValue
)
)
[path2] => Array
(
[dir] => Array
(
[file3] => someValue
[file4] => someValue
)
)
)
Thanks a lot!
It can be done without recursion
$path = array(
'path/to/directory/file1',
'path/directory/file2',
'path2/dir/file3',
'path2/dir/file4');
$arr = [];
$someValue = 'someValue';
foreach ( $path as $p ) {
$segments = explode('/', $p);
$str = '';
$p = &$arr;
foreach ( $segments as $s ) {
if (! isset($p[$s] ) ) $p[$s] = array();
$p = &$p[$s];
}
$p = $someValue;
}
print_r($arr);
I have an array that looks like this:
$array = array (
[level_1] => array (
[level_2] => array (
[level_3] => something
)
),
[level_12] => array (
[level_2] => somethingelse
),
[level_13] => array (
[level_22] => array (
[level_3] => something
)
),
);
The keys or values aren't always unique but the branches are.
And I have a string that looks like this:
$string = 'level_1-level_2-level_3';
Those are the keys for a branch.
And I need to somehow get the value from the array based on that string?
Like this:
$string_array = explode('-', $string);
$array[$string_array[0]][$string_array[1]][$string_array[2]] // something
But since the depth can be different this is not a viable solution...
Try this simple example, no need for a recursive function:
function get_item( $path, $array )
{
$paths = explode( '-', $path );
$result = $array;
foreach ( $paths as $path) {
isset( $result[$path] ) ? $result = $result[$path] : $result = false;
}
return $result;
}
$path = 'level_1-level_2-level_3';
echo get_item( $path, $array );
Try this:
$array = array (
'level_1' => array (
'level_2' => array (
'level_3' => 'something'
)
),
'level_12' => array (
'level_2' => 'somethingelse'
),
'level_13' => array (
'level_22' => array (
'level_3' => 'something'
)
),
);
$string = 'level_1-level_2-level_3';
$keys = explode('-', $string);
echo getItemIterative($keys, $array);
echo "\n";
echo getItemRecursive($keys, $array);
function getItemIterative($keys, $array)
{
$value = null;
foreach ($keys as $key) {
if ($value == null) {
$value = $array[$key];
}
if (is_array($value) && array_key_exists($key, $value)) {
$value = $value[$key];
}
}
return $value;
}
function getItemRecursive($keys, $array)
{
$key = array_shift($keys);
$value = $array[$key];
if (empty($keys)) {
return $value;
} else {
return getItemRecursive($keys, $value);
}
}
Make a $result variable which initially points to the root of the array, and loop through the levels of your $string_array 'til $result points at the leaf you were looking for.
// stuff you already have:
$array = array(...); // your big array
$string = 'level_1-level_2-level_3';
$string_array = explode('-', $string);
// new stuff:
$result = $array;
foreach ($string_array as $level) {
$result = $result[$level];
}
echo $result; // 'something'
Working example: Ideone
I'm having a problem with this. I have a string that looks like this:
coilovers[strut_and_individual_components][complete_strut][][achse]
And i want to convert it to to array that looks like this:
[coilovers] => Array
(
[strut_and_individual_components] => Array
(
[complete_strut]=> Array
(
[1] => Array
(
[achse] => some_value
)
[2] => Array
(
[achse] => some_value
)
)
)
)
is it possible?
Here is a quick implementation of a parser that will attempt to parse this string:
$input = 'coilovers[strut_and_individual_components][complete_strut][][achse]';
$output = array();
$pointer = &$output;
while( ($index = strpos( $input, '[')) !== false) {
if( $index != 0) {
$key = substr( $input, 0, $index);
$pointer[$key] = array();
$pointer = &$pointer[$key];
$input = substr( $input, $index);
continue;
}
$end_index = strpos( $input, ']');
$array_key = substr( $input, $index + 1, $end_index - 1);
$pointer[$array_key] = array();
$pointer = &$pointer[$array_key];
$input = substr( $input, $end_index + 1);
}
print_r( $output);
Essentially, we are iterating the string to find matching [ and ] tags. When we do, we take the value within the brackets as $array_key and add that into the $output array. I use another variable $pointer by reference that is pointing to the original $output array, but as the iteration goes, $pointer points to the last element added to $output.
It produces:
Array
(
[coilovers] => Array
(
[strut_and_individual_components] => Array
(
[complete_strut] => Array
(
[] => Array
(
[achse] => Array
(
)
)
)
)
)
)
Note that I've left the implementation of [] (an empty array key) and setting the values in the last index (some_value) as an exercise to the user.
Well I've found an another answer for it and it looks like this:
private function format_form_data(array $form_values) {
$reformat_array = array();
$matches = array();
$result = null;
foreach($form_values as $value) {
preg_match_all("/\[(.*?)\]/", $value["name"], $matches);
$parsed_product_array = $this->parse_array($matches[1], $value["value"]);
$result = array_push($reformat_array, $parsed_product_array);
}
return $result;
}
private function parse_array(array $values, $value) {
$reformat = array();
$value_carrier_key = end($values);
foreach (array_reverse($values) as $arr) {
$set_value_carrier = array($arr => $reformat);
if($arr == $value_carrier_key) {
$set_value_carrier = array($arr => $value);
}
$reformat = empty($arr) ? array($reformat) : $set_value_carrier;
}
return $reformat;
}
where array $form_values is:
Array
(
[name] => '[coilovers][strut_and_individual_components][complete_strut][][achse]',
[value] => 'some_value'
)
No. If you evaluate the string you will get invalid PHP.
If you want to store a PHP Array as string and get it loaded back as PHP Array, have a look at serialize and unserialize functions.
Of course you can build an array from your string, but you'll have to write a parser.
The solution I propose:
function format_form_data(array $data) {
$matches = array();
$result = [];
foreach($data as $key => $value) {
preg_match_all("/\[(.*?)\]/", $key, $matches);
$matches = array_reverse($matches[1]);
$matches[] = substr( $key, 0, strpos($key, '['));;
foreach ($matches as $match) {
$value = [$match=>$value];
}
$result = array_replace_recursive($result, $value);
}
return $result;
}
I need to extract a associative array keys into a string and implode with "/" or any character/symbols.
For eg:
$array = array([key1] =>
array([key11] =>
array([key111] => 'value111',
[key112] => 'value112',
[key113] => 'value113',
),
),
);
I need an output as below array:
array([0] => 'key1/key11/key111',[1] => 'key1/key11/key112', [2] => 'key1/key11/key112');
I've edited an answer given here and came up with the following code.
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);
print_r($outputArray);
Input:
Array
(
[key1] => Array
(
[key11] => Array
(
[key111] => value111
[key112] => value113
[key113] => value113
)
)
)
Output:
Array
(
[0] => key1/key11/key111
[1] => key1/key11/key112
[2] => key1/key11/key113
)
Works for different depth of array:
function getKeys($array, $prefix='', $separator = '/') {
$return = array();
foreach($array as $key => $value) {
if (!is_array($value)) $return[] = $prefix . $key;
else $return = array_merge($return, getKeys($value, $prefix . $key . separator), $separator);
}
return $return;
}
$keys = getKeys($array, '', '#');
See online fiddle http://ideone.com/krU4Xn
you could do something like...
$mapArray = array();
$symbol = '/';
foreach($array as $k =>$v)
foreach($v as $k1 =>$v1)
foreach($v1 as $k2 =>$v2)
$mapArray[] = $k.$symbol.$k1.$symbol.$k2;
also this obviously only works in this particular case, if it needs to be more generic it can be done, but I think this should get you started.