Determining a position in an array with a string

I have an interesting problem ... I am creating an API where the user indicates the location of an element in the array through a string. Like this:

$path = "group1.group2.group3.element"; 

Given this line, I have to save some value in the right place in the array. For the example above, this would be:

 $results['group1']['group2']['group3']['element'] = $value; 

Of course, the code should be common to any user of $path who throws me.

How would you solve this?

UPDATE - SOLUTION : using both ern0 (similar to mine) and the nikc answer as inspiration, this is the solution I decided:

 // returns reference to node in $collection as referenced by $path. For example: // $node =& findnode('dir.subdir', $some_array); // In this case, $node points to $some_array['dir']['subdir']. // If you wish to create the node if it doesn't exist, set $force to true // (otherwise it throws exception if the node is not found) function &findnode($path, &$collection, $force = false) { $parts = explode('.', $path); $where = &$collection; foreach ($parts as $part) { if (!isset($where[$part])) { if ($force) $where[$part] = array(); else throw new RuntimeException('path not found'); } $where =& $where[$part]; } return $where; } $results = array(); $value = '1'; try { $bucket =& findnode("group1.group2.group3.element", $results, true); } catch (Exception $e) { // no such path and $force was false } $bucket = $value; // read or write value here var_dump($results); 

Thanks everyone for the answers, it was a great exercise! :)

+4
source share
5 answers

I may not know PHP very well, but I could not find a language element that can insert an element into an array at any depth.

A quick and dirty solution to eval () , but as we know, this is evil. But if you look at the input (dashed form) and the result (array indices) for more than 10 seconds, you will ask: why are we thinking about creating arrays with custom depth and in general, because it took only two simple * str_replace () * s to convert result to result.

Edit: here is the eval version, do not use it:

  $x = str_replace(".","][",$path); $x = '$result[' . $x . '] = "' . $value . '";'; eval($x); 

Another way is to use indirection to climb deep into a tree without knowing its depth:

 $path = "group1.group2.group3.element"; $value = 55; $x = explode(".",$path); $result = Array(); $last = &$result; foreach ($x as $elem) { $last[$elem] = Array(); $last = &$last[$elem]; } $last = $value; echo("<pre>$path=$value\n"); print_r($result); 

Gathering links to array elements for later completion is a very useful PHP function.

+2
source

Let me throw my own answer in the mix: :)

 $path = "group1.group2.group3.element"; $results = array(); $parts = explode('.', $path); $where = &$results; foreach ($parts as $part) { $where =& $where[$part]; } $where = $value; 
+2
source

I donโ€™t think it will be the best, but I tried to find a solution as an exercise for myself :)

  $path = "group1.group2.group3.element"; //path $value = 2; //value $results = array(); //an array $t = explode(".",$path); //explode the path into an array $n=count($t); //number of items $i=0; //a counter variable $r = &$results; //create the reference to the array foreach($t as $p) //loop through each item { if($i == $n-1) //if it reached the last element, then insert the value { $r[$p] = $value; break; } else //otherwise create the sub arrays { $r[$p] = array(); $r = &$r[$p]; $i++; } } print_r($results); //output the structure of array to verify it echo "<br>Value is: " . $results['group1']['group2']['group3']['element']; //output the value to check 

I hope he will work on your side too .. :)

+1
source

As I commented on your own answer, you are on the right track. Actually very close. However, I prefer to use recursion, but this is only a preference, all this could be done in a linear loop.

To find node (read), this works:

 function &findnode(array $path, &$collection) { $node = array_shift($path); if (array_key_exists($node, $collection)) { if (count($path) === 0) { // When we are at the end of the path, we return the node return $collection[$node]; } else { // Otherwise, we descend a level further return findnode($path, $collection[$node]); } } throw new RuntimeException('path not found'); } $collection = array( 'foo' => array( 'bar' => array( 'baz' => 'leafnode @ foo.bar.baz' ) ) ); $path = 'foo.bar.baz'; $node =& findnode(explode('.', $path), $collection); var_dump($node); // Output: 'leafnode @ foo.bar.baz' 

To introduce node (write), we need to change the logic a bit to create a path along the way.

 function &findnode(array $path, &$collection, $create = false) { $node = array_shift($path); // If create is set and the node is missing, we create it if ($create === true && ! array_key_exists($node, $collection)) { $collection[$node] = array(); } if (array_key_exists($node, $collection)) { if (count($path) === 0) { // When we are at the end of the path, we return the node return $collection[$node]; } else { // Otherwise, we descend a level further return findnode($path, $collection[$node], $create); } } throw new RuntimeException('path not found'); } $collection = array( 'foo' => array( 'bar' => array( 'baz' => 'leafnode @ foo.bar.baz' ) ) ); $path = explode('.', 'baz.bar.foo'); $leaf = array_pop($path); // Store the leaf node // Write $node =& findnode($path, $collection, true); $node[$leaf] = 'foo.bar.baz injected'; var_dump($collection); // Will have the new branch 'baz.bar.foo' with the injected value at the leaf 

To make it all beautiful and beautiful, you would wrap the read and write operations in your own functions. Most likely, all this is inside your own class.

Thus, using the above version of findnode , we can use these two functions to read and write from / to your collection array.

 function read($path, $collection) { $path = explode('.', $path); $val =& findnode($path, $collection); return $val; } function write($value, $path, $collection) { $path = explode('.', $path); $leaf = array_pop($path); $node =& findnode($path, $collection, true); $node[$leaf] = $value; } 

NB! This is not a complete solution or the most elegant. But you can probably figure out the rest for yourself.

+1
source

I hope the below code will work,

 $path = "group1.group2.group3.element"; $tempArr = explode('.', $path); $results = array(); $arrStr = '$results'; $value = 'testing'; foreach( $tempArr as $ky=>$val) { $arrStr .= "['".$val."']"; ( $ky == count($tempArr) - 1 ) ? $arrStr .= ' = $value;' : ''; } eval($arrStr); print_r($results); 
0
source

Source: https://habr.com/ru/post/1387330/


All Articles