This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
PHP: Use a string as an array index path to retreive a value
I have an array like so:
$array['image']['comment'] = 'something';
$array['image']['tag'] = 'happy';
$array['image']['colors']['blue'] = '12345';
If I have the path to each element in a string, how can I set or get the array value?
e.g where $path = 'image/colors/blue'; the below function should return 12345
function get_array($array, $path)
{
//what goes here?
}
function set_array($array, $path, $value)
{
//what goes here?
}
Try this:
$arr = array('a' => 'A', 'b' => array('c' => 'C', 'd' => array('e'=>'E')));
function read_array($array, $path)
{
if($pos = strpos($path, '/') !== false){
$key = substr($path, 0, $pos);
$restOfKey = substr($path, $pos + 1);
return read_array($array[$key], $restOfKey);
} else {
$key = $path;
return $array[$key];
}
}
echo read_array($arr, 'a'); //A
echo read_array($arr, 'b/c'); //C
echo read_array($arr, 'b/d/e'); //E
You should of course add error checking and all.
Try this. Very basic but it might provide you a jump off point:
$array['image']['comment'] = 'something';
$array['image']['tag'] = 'happy';
$array['image']['colors']['blue'] = '12345';
function get_array($array, $path) {
if(strpos('/', $path) > 0) {
list($first, $second, $third) = explode('/', $path);
return $array[$first][$second][$third];
}
}
get_array($array, 'image/colours/blue');
You could just call split or explode on the path string and insert the individual values into each dimension. This isn't unbounded, but i'm assuming you have a rough idea with this example of the depth this could go.
function getPathVal($array, $path) {
$path_array = explode("/", $path);
$cnt = count($path_array);
if ($cnt == 3) {
return $array[$path_array[0]][$path_array[1]][$path_array[2]];
} else if ($cnt == 2) {
return $array[$path_array[0]][$path_array[1]];
} else if ($cnt == 1) {
return $array[$path_array[0]];
} else {
return "";
}
}
Related
I'm trying to resolve [This exercise][1]...
I'm writing the follow code:
$steps=8;
$path=['U','D','D','D','U','D','U','U'];
function countingValleys($steps, $path) {
// Write your code here
$sea=0;
$valley=0;
$key=0;
function check($steps, $path,$valley,$key,$sea){
($path[$key]=='D')?$sea--:$sea++;
if($sea<0) $valley++;
while($sea<0){
$key++;
if($key==$steps) return $valley; else ($path[$key]=='D')?$sea--:$sea++;
}
$key++;
if($key==$steps) return $valley; else check($steps, $path,$valley,$key,$sea);
}
$Return=check($steps, $path,$valley,$key,$sea);
return $Return;
}
$Return=countingValleys($steps, $path);
echo $Return;
suddenly it returns an empty string instead the result it should... Can you help me?
Thanks
[1]: https://www.hackerrank.com/challenges/counting-valleys/problem?h_l=interview&playlist_slugs%5B%5D=interview-preparation-kit&playlist_slugs%5B%5D=warmup
It's empty string because $Return=countingValleys($steps, $path); takes null value.
The reason is that in check() method you return $valley or you call recursively check() but you also have to return it otherwise the method act like it's void method.
<?php
$steps = 8;
$path = ['U', 'D', 'D', 'D', 'U', 'D', 'U', 'U'];
function countingValleys($steps, $path)
{
// Write your code here
$sea = 0;
$valley = 0;
$key = 0;
function check($steps, $path, $valley, $key, $sea)
{
($path[$key] == 'D') ? $sea-- : $sea++;
if ($sea < 0) $valley++;
while ($sea < 0) {
$key++;
if ($key == $steps) return $valley; else ($path[$key] == 'D') ? $sea-- : $sea++;
}
$key++;
if ($key == $steps) return $valley; else return check($steps, $path, $valley, $key, $sea);
}
$Return = check($steps, $path, $valley, $key, $sea);
return $Return;
}
$Return = countingValleys($steps, $path);
echo $Return;
// output 1
I have a multidimensional array that's contains all user data , and I've build a function to get array value with the given key .
the problem is that the array is multidimensional array , and I don't know how many level .
this is the function
function getUserSessionData($key)
{
$arrKeys = explode('.', $key);
if(count($arrKeys) == 1){
if(isset($_SESSION['user_data'][$arrKeys[0]])){
return $_SESSION['user_data'][$arrKeys[0]];
}
}
else{
if(isset($_SESSION['user_data'][$arrKeys[0]][$arrKeys[1]])){
return $_SESSION['user_data'][$arrKeys[0]][$arrKeys[1]];
}
}
return 0;
}
and this is an example of the call.
getUserSessionData('profile.firstName');
The (.) indicates of level of the array .
the function is support only tow levels .. is there any way to enhance this function so it can support more than tow levels ??
Sure, use a looping structure:
function getUserSessionData($key) {
$parts = explode('.', $key);
$data = $_SESSION["user_data"];
while (count($parts) > 0) {
$part = array_shift($parts);
$data = $data[$part];
}
return $data;
}
Or independently of the session:
function resolveKey($array, $key) {
$parts = explode('.', $key);
while (count($parts) > 0) {
$part = array_shift($parts);
$array = $array[$part];
}
return $array;
}
echo resolveKey(array(
"foo" => array(
"bar" => array(
"baz" => "ipsum"
)
)
), "foo.bar.baz"); // "ipsum"
echo resolveKey($_SESSION["user_data"], 'profile.firstName');
Here's a PHP-Fiddle
function getUserSessionData($key){
$arrKeys = explode('.', $key);
$data = $_SESSION['user_data'];
foreach($arrKeys as $k){
if(isset($data[$k])) $data = $data[$k];
else return false;
}
return $data;
}
Example usage:
session_start();
$_SESSION['user_data'] = [];
$_SESSION['user_data']['user'] = [];
$_SESSION['user_data']['user']['name'] = [];
$_SESSION['user_data']['user']['name']['first'] = "robert";
echo getUserSessionData("user.name.first"); // echos "robert"
Thank you #Halcyon
you've been very helpful.
but I've modified your function to get it to work .
this is the new function
function getUserSessionData($key) {
$data = Yii::app()->session['account_data']['user_data'];
$parts = explode('.', $key);
while (count($parts) > 0) {
$part = $parts[0];
if(!isset($data[$part])){
return 0;
}
$data = $data[$part];
array_shift($parts);
}
return $data;
}
Given a multidimensional array or dictionary $array.
And assuming that $array['foo']['bar']['baz'] = 'something';
Is there a way other than via an eval statement for me use the multi-dimentional index foo/bar/baz? (The use case is in creating the index dynamically i.e. The function does not know what /foo/bar/baz/ is).
The only way I could figure to do this was:
$item = testGetIndex($array, "'foo']['bar']['baz'");
function testGetIndex($array, $index) {
eval('$item = $array[' . $index . '];');
return $item;
}
Note:
I should mention that I do not want to search this array. This is a weird use case. I am being passed a very large multi dimensional array and it's ugly to have to use constructs like..
$array[foo][bar]..[baz] to make modifications to the array.
Blatently reusing my answer here:
function recurseKeys(array $keys,array $array){
$key = array_shift($keys);
if(!isset($array[$key])) return null;
return empty($keys) ?
$array[$key]:
recurseKeys($keys,$array[$key];
}
$values = recurseKeys(explode('/','foo/bar/baz'),$yourArray);
edit: as Jack pointed out, recursion is not needed:
function findByKey(array $keys,array $array){
while(!is_null($key = array_shift($keys))){
if(!isset($array[$key])) return null;
$array = $array[$key];
}
return $array;
}
$values = findByKey(explode('/','foo/bar/baz'),$yourArray);
To modify an array using a path:
function setPath(&$root, $path, $value)
{
$paths = explode('/', $path);
$current = &$root;
foreach ($paths as $path) {
if (isset($current[$path])) {
$current = &$current[$path];
} else {
return null;
}
}
return $current = $value;
}
$path = 'foo/bar/baz';
$root = array('foo' => array('bar' => array('baz' => 'something')));
setPath($root, $path, '123');
You can tweak the function to just return a reference to the element you wish to change:
function &getPath(&$root, $path)
{
$paths = explode('/', $path);
$current = &$root;
foreach ($paths as $path) {
if (isset($current[$path])) {
$current = &$current[$path];
} else {
return null;
}
}
return $current;
}
$x = &getPath($root, $path);
$x = 456; // $root['foo']['bar']['baz'] == 456
A simple loop can make it, like:
function get(array $array, $keys) {
$val = $array;
foreach (explode('/', $keys) as $part) {
if (!isset($val[$part])) {
return null;
}
$val = $val[$part];
}
return $val;
}
$array['foo']['bar']['baz'] = 'something';
echo get($array, 'foo/bar/baz');
http://ideone.com/vcRvXW
Edit:
For modification, just use references:
function set(array &$array, $keys, $value) {
$val = &$array;
foreach (explode('/', $keys) as $part) {
if (!isset($val[$part])) {
$val[$part] = array();
}
$val = &$val[$part];
}
$val = $value;
}
http://ideone.com/WUNhF6
If I have an array which corresponds to successively recursive keys in another array, what is the best way to to assign a value to that "path" (if you want to call it that)?
For example:
$some_array = array();
$path = array('a','b','c');
set_value($some_array,$path,'some value');
Now, $some_array should equal
array(
'a' => array(
'b' => array(
'c' => 'some value'
)))
At the moment, I am using the following:
function set_value(&$dest,$path,$value) {
$addr = "\$dest['" . implode("']['", $path) . "']";
eval("$addr = \$value;");
}
Obviously, this is a very naive approach and poses a security risk, so how would you do it?
Recursive solution (not tested):
function set_value(&$dest,$path,$value) {
$index=array_shift($path);
if(empty($path)){
// on last level
$dest[$index]=$value;
}
else{
// descending to next level
set_value($dest[$index],$path,$value);
}
}
Wow, reminds me of Lisp.
Yea, eval is generally not the best idea.
Personally, I would simply iterate:
function set_value(&$dest,$path,$value) {
$val =& $dest;
for($i = 0; $i > count($path) - 1; $i++) {
$val =& $val[$i];
}
$val[$path[$i]] = $value;
}
If you're in PHP 5 you can probably get rd of some of those '&' too
function set_value(&$dest, $path, $value) {
$dest = array(array_pop($path) => $value);
for($i = count($path) - 1; $i >= 0; $i--) {
$dest = array($path[$i] => $dest);
}
}
function set_value(&$dest, $path, $value)
{
# allow for string paths of a/b/c
if (!is_array($path)) $path = explode('/', $path);
$a = &$dest;
foreach ($path as $p)
{
if (!is_array($a)) $a = array();
$a = &$a[$p];
}
return $a = $value;
}
set_value($a, 'a/b/c', 'foo');
Updated to work with keys that don't yet exist, and to accept either an array or a string path.
I need to check if a key exists and return its value if it does.
Key can be an array with subkeys or endkey with a value.
$_SESSION['mainKey']['testkey'] = 'value';
var_dump(doesKeyExist('testkey'));
function doesKeyExist($where) {
$parts = explode('/',$where);
$str = '';
for($i = 0,$len = count($parts);$i<$len;$i++) {
$str .= '[\''. $parts[$i] .'\']';
}
$keycheck = '$_SESSION[\'mainKey\']' . $str;
if (isset(${$keycheck})) {
return ${$keycheck};
}
// isset($keycheck) = true, as its non-empty. actual content is not checked
// isset(${$keycheck}) = false, but should be true. ${$var} forces a evaluate content
// isset($_SESSION['mainKey']['testkey']) = true
}
Using PHP 5.3.3.
Instead of building the string, just check if the key exists within your loop.
For instance:
function doesKeyExist($where) {
$parts = explode('/',$where);
$currentPart = $_SESSION['mainKey'];
foreach($parts as $part) {
if (!isset($currentPart[$part])) {
return false;
}
$currentPart = $currentPart[$part];
}
return true;
}
function getByKeys($keys, $array) {
$value = $array;
foreach (explode('/', $keys) as $key) {
if (isset($value[$key])) {
$value = $value[$key];
} else {
return null;
}
}
return $value;
}
Perhaps I'm misunderstanding the question, but this would appear to be the simplest way of doing it:
function getKey($arr, $key) {
if (array_key_exists($key, $arr)) {
return $arr[$key];
} else {
return false;
}
}
$value = getKey($_SESSION['mainKey'], 'testkey');
You should use $$keycheck, not ${$keycheck}.
The last notation is only if you use the variable inside a string (e.g. "${$keycheck}")
See http://php.net/manual/en/language.variables.variable.php for more details about variable variables
You might want to use the eval() php function for this.
function doesKeyExist($where) {
$parts = explode('/',$where);
$str = '';
for($i = 0,$len = count($parts);$i<$len;$i++) {
$str .= '["'. $parts[$i] .'"]';
}
eval('$keycheck = $_SESSION["mainKey"]' . $str . ';');
if (isset($keycheck)) {
return $keycheck;
}
}
HTH