Convert delimited string into array key path and assign value - php

I have a string like this:
$string = 'one/two/three/four';
which I turn it into a array:
$keys = explode('/', $string);
This array can have any number of elements, like 1, 2, 5 etc.
How can I assign a certain value to a multidimensional array, but use the $keys I created above to identify the position where to insert?
Like:
$arr['one']['two']['three']['four'] = 'value';
Sorry if the question is confusing, but I don't know how to explain it better

This is kind of non-trivial because you want to nest, but it should go something like:
function insert_using_keys($arr, $keys, $value){
// we're modifying a copy of $arr, but here
// we obtain a reference to it. we move the
// reference in order to set the values.
$a = &$arr;
while( count($keys) > 0 ){
// get next first key
$k = array_shift($keys);
// if $a isn't an array already, make it one
if(!is_array($a)){
$a = array();
}
// move the reference deeper
$a = &$a[$k];
}
$a = $value;
// return a copy of $arr with the value set
return $arr;
}

$string = 'one/two/three/four';
$keys = explode('/', $string);
$arr = array(); // some big array with lots of dimensions
$ref = &$arr;
while ($key = array_shift($keys)) {
$ref = &$ref[$key];
}
$ref = 'value';
What this is doing:
Using a variable, $ref, to keep track of a reference to the current dimension of $arr.
Looping through $keys one at a time, referencing the $key element of the current reference.
Setting the value to the final reference.

You'll need to first make sure the key's exist, then assign the value. Something like this should work (untested):
function addValueByNestedKey(&$array, $keys, $value) {
$branch = &$array;
$key = array_shift($keys);
// add keys, maintaining reference to latest branch:
while(count($keys)) {
$key = array_pop($keys);
if(!array_key_exists($key, $branch) {
$branch[$key] = array();
}
$branch = &$branch[$key];
}
$branch[$key] = $value;
}
// usage:
$arr = array();
$keys = explode('/', 'one/two/three/four');
addValueByNestedKey($arr, $keys, 'value');

it's corny but:
function setValueByArrayKeys($array_keys, &$multi, $value) {
$m = &$multi
foreach ($array_keys as $k){
$m = &$m[$k];
}
$m = $value;
}

$arr['one']['two']['three']['four'] = 'value';
$string = 'one/two/three/four';
$ExpCheck = explode("/", $string);
$CheckVal = $arr;
foreach($ExpCheck AS $eVal){
$CheckVal = $CheckVal[$eVal]??false;
if (!$CheckVal)
break;
}
if ($CheckVal) {
$val =$CheckVal;
}
this will give u your value in array.

Related

php access to specific position of multidimensional array by its keys and set it

In PHP we can do things like these:
Class Example {
...
}
$example = 'Example';
$object = new $example();
Or the use of variable variables:
$hour = 18;
$greets = array('Good morning','Good afternoon','Good evening');
$values = array(13,21,23);//people is sleeping at 23PM, so they don't greet.
$n = count($values);
$greet = 'greets';
for($i=0;$i<$n;$i++){
if($hour < $values[$i]){
echo 'hello, '.${$greet}[$i];
break;
}
}
And others..
I wonder if it would be possible to access directly to a specific index of a multidimensional array in a similar way. Something like:
$array = array(...); //multidimensional array.
$position = '[0][4][3]';
print_r($array$position);
Thanks in advance.
UPDATE
I'm so sorry because I finished my question in a wrong way.
I need to set the multimesional array and add a value. i.e:
$array$position = $data;
You could implement it yourself with a custom function:
function getValueFromMultiDimensionalArray( array $array, string $key )
{
$keys = explode('][', $key);
$value = $array;
foreach ($keys as $theKey) {
// remove the opening or closing bracket if present
$theKey = str_replace([ '[', ']' ], '', $theKey);
if (!isset($value[$theKey])) {
return null;
}
$value = $value[$theKey];
}
return $value;
}
You can define path as dot separated , check the following solution
function getValueByKey($a,$p){
$c = $a;
foreach(explode('.',$p) as $v){
if(!array_key_exists($v, $c)) return null;
$c = $c[$v];
}
return $c;
}
You can use this function as
$path = '1.2.3.0';
$indexValue = getValueByKey($array, $path);
Nope, this is not possible.
The only thing you can do is to implement ArrayAccess interface, which allows to access instances with [] operator. But you will have to define the logic yourself.
class MyClass implements ArrayAccess
{
...
}
$x = new MyClass([0=>[4=>[3=>'hello world']]]);
$position = '[0][4][3]';
echo $x[$position]; //hello world

Pick a random key of an array but forcing one of the values

Let's suppose I have an array of arrays:
$A=array();
$A['lemonade']=array('a','b','g');
$A['tree']=array('a','b','f');
$A['willpower']=array('a','b','g');
How may i randomly grab one key of $A, but only of those containing 'g' in $A[n][2]?
The direct approach is to iterate though them all, create a new array containing only the arrays containing g, and then grabbing a random key in that new array.
$bro=array();
foreach($A as $k=>$hijito){
if($hijito[2]=='g'){
$bro[$k]=$hijito;
}
}
$theKeyIWant=array_rand($bro);
But I wonder if there is some other fancier way to approach this.
There is also this method using array_walk(DEMO):
$A = array();
$A['lemonade'] = array('a','b','g');
$A['tree'] = array('a','b','f');
$A['willpower'] = array('a','b','g');
$bro = $A;
array_walk($A, function($item, $key) use (&$bro)
{
if($item[2] != 'g')
{
unset($bro[$key]);
}
});
var_dump($bro);
Try This. First I filter the array and then get random key.
$A=array();
$A['lemonade']=array('a','b','g');
$A['tree']=array('a','b','f');
$A['willpower']=array('a','b','g');
$theKey = array_rand($filteredArr = array_filter($A, function($arr){
return ($arr[2] == 'g');
}));
echo $theKey;
try it with Array Iterator. have a look on below solution:
$n = 2; //key which need to be checked
$v = 'g'; //value which need to be checked
$key_array = array();
$it = new RecursiveIteratorIterator(new RecursiveArrayIterator($A));
foreach ($it as $key => $val) {
$pkey = $it->getSubIterator($it->getDepth() - 1)->key(); //get parent key
if($key == $n && $val == $v){
$key_array[$pkey] = $A[$pkey];
}
}
print_r($key_array); //desired array
print_r(array_rand($key_array)); //desired key

PHP - dynamically add dimensions to array

I have a :
$value = "val";
I also have an array :
$keys = ['key1', 'key2', 'key3'...]
The keys in that array are dynamically generated, and can go from 2 to 10 or more entries.
My goal is getting this :
$array['key1']['key2']['key3']... = $value;
How can I do that ?
Thanks
The easiest, and least messy way (ie not using references) would be to use a recursive function:
function addArrayLevels(array $keys, array $target)
{
if ($keys) {
$key = array_shift($keys);
$target[$key] = addArrayLevels($keys, []);
}
return $target;
}
//usage
$keys = range(1, 10);
$subArrays = addARrayLevels($keys, []);
It works as you can see here.
How it works is really quite simple:
if ($keys) {: if there's a key left to be added
$key = array_shift($keys); shift the first element from the array
$target[$key] = addArrayLevels($keys, []);: add the index to $target, and call the same function again with $keys (after having removed the first value). These recursive calls will go on until $keys is empty, and the function simply returns an empty array
The downsides:
Recursion can be tricky to get your head round at first, especially in complex functions, in code you didn't write, but document it well and you should be fine
The pro's:
It's more flexible (you can use $target as a sort of default/final assignment variable, with little effort (will add example below if I find the time)
No reference mess and risks to deal with
Example using adaptation of the function above to assign value at "lowest" level:
function addArrayLevels(array $keys, $value)
{
$return = [];
$key = array_shift($keys);
if ($keys) {
$return[$key] = addArrayLevels($keys, $value);
} else {
$return[$key] = $value;
}
return $return;
}
$keys = range(1, 10);
$subArrays = addARrayLevels($keys, 'innerValue');
var_dump($subArrays);
Demo
I don't think that there is built-in function for that but you can do that with simple foreach and references.
$newArray = [];
$keys = ['key1', 'key2', 'key3'];
$reference =& $newArray;
foreach ($keys as $key) {
$reference[$key] = [];
$reference =& $reference[$key];
}
unset($reference);
var_dump($newArray);

array values to nested array with PHP

I'm trying to figure out how I can use the values an indexed array as path for another array. I'm exploding a string to an array, and based on all values in that array I'm looking for a value in another array.
Example:
$haystack['my']['string']['is']['nested'] = 'Hello';
$var = 'my#string#is#nested';
$items = explode('#', $var);
// .. echo $haystack[... items..?]
The number of values may differ, so it's not an option to do just $haystack[$items[0][$items[1][$items[2][$items[3]].
Any suggestions?
You can use a loop -
$haystack['my']['string']['is']['nested'] = 'Hello';
$var = 'my#string#is#nested';
$items = explode('#', $var);
$temp = $haystack;
foreach($items as $v) {
$temp = $temp[$v]; // Store the current array value
}
echo $temp;
DEMO
You can use a loop to grab each subsequent nested array. I.e:
$haystack['my']['string']['is']['nested'] = 'Hello';
$var = 'my#string#is#nested';
$items = explode('#', $var);
$val = $haystack;
foreach($items as $key){
$val = $val[$key];
}
echo $val;
Note that this does no checking, you likely want to check that $val[$key] exists.
Example here: http://codepad.org/5ei9xS91
Or you can use a recursive function:
function extractValue($array, $keys)
{
return empty($keys) ? $array : extractValue($array[array_shift($keys)], $keys) ;
}
$haystack = array('my' => array('string' => array('is' => array('nested' => 'hello'))));
echo extractValue($haystack, explode('#', 'my#string#is#nested'));

php call array from string

I have a string that contains elements from array.
$str = '[some][string]';
$array = array();
How can I get the value of $array['some']['string'] using $str?
This will work for any number of keys:
$keys = explode('][', substr($str, 1, -1));
$value = $array;
foreach($keys as $key)
$value = $value[$key];
echo $value
You can do so by using eval, don't know if your comfortable with it:
$array['some']['string'] = 'test';
$str = '[some][string]';
$code = sprintf('return $array%s;', str_replace(array('[',']'), array('[\'', '\']'), $str));
$value = eval($code);
echo $value; # test
However eval is not always the right tool because well, it shows most often that you have a design flaw when you need to use it.
Another example if you need to write access to the array item, you can do the following:
$array['some']['string'] = 'test';
$str = '[some][string]';
$path = explode('][', substr($str, 1, -1));
$value = &$array;
foreach($path as $segment)
{
$value = &$value[$segment];
}
echo $value;
$value = 'changed';
print_r($array);
This is actually the same principle as in Eric's answer but referencing the variable.
// trim the start and end brackets
$str = trim($str, '[]');
// explode the keys into an array
$keys = explode('][', $str);
// reference the array using the stored keys
$value = $array[$keys[0][$keys[1]];
I think regexp should do the trick better:
$array['some']['string'] = 'test';
$str = '[some][string]';
if (preg_match('/\[(?<key1>\w+)\]\[(?<key2>\w+)\]/', $str, $keys))
{
if (isset($array[$keys['key1']][$keys['key2']]))
echo $array[$keys['key1']][$keys['key2']]; // do what you need
}
But I would think twice before dealing with arrays your way :D

Categories