How to Access and Manipulate Multi-dimensional Array by Key Names/Path

How to access and manipulate multi-dimensional array by key names / path?

Assuming $path is already an array via explode (or add to the function), then you can use references. You need to add in some error checking in case of invalid $path etc. (think isset):

$key = 'b.x.z';
$path = explode('.', $key);

Getter

function get($path, $array) {
//$path = explode('.', $path); //if needed
$temp =& $array;

foreach($path as $key) {
$temp =& $temp[$key];
}
return $temp;
}

$value = get($path, $arr); //returns NULL if the path doesn't exist

Setter / Creator

This combination will set a value in an existing array or create the array if you pass one that has not yet been defined. Make sure to define $array to be passed by reference &$array:

function set($path, &$array=array(), $value=null) {
//$path = explode('.', $path); //if needed
$temp =& $array;

foreach($path as $key) {
$temp =& $temp[$key];
}
$temp = $value;
}

set($path, $arr);
//or
set($path, $arr, 'some value');

Unsetter

This will unset the final key in the path:

function unsetter($path, &$array) {
//$path = explode('.', $path); //if needed
$temp =& $array;

foreach($path as $key) {
if(!is_array($temp[$key])) {
unset($temp[$key]);
} else {
$temp =& $temp[$key];
}
}
}
unsetter($path, $arr);

*The original answer had some limited functions that I will leave in case they are of use to someone:

Setter

Make sure to define $array to be passed by reference &$array:

function set(&$array, $path, $value) {
//$path = explode('.', $path); //if needed
$temp =& $array;

foreach($path as $key) {
$temp =& $temp[$key];
}
$temp = $value;
}

set($arr, $path, 'some value');

Or if you want to return the updated array (because I'm bored):

function set($array, $path, $value) {
//$path = explode('.', $path); //if needed
$temp =& $array;

foreach($path as $key) {
$temp =& $temp[$key];
}
$temp = $value;

return $array;
}

$arr = set($arr, $path, 'some value');

Creator

If you wan't to create the array and optionally set the value:

function create($path, $value=null) {
//$path = explode('.', $path); //if needed
foreach(array_reverse($path) as $key) {
$value = array($key => $value);
}
return $value;
}

$arr = create($path);
//or
$arr = create($path, 'some value');

For Fun

Constructs and evaluates something like $array['b']['x']['z'] given a string b.x.z:

function get($array, $path) {
//$path = explode('.', $path); //if needed
$path = "['" . implode("']['", $path) . "']";
eval("\$result = \$array{$path};");

return $result;
}

Sets something like $array['b']['x']['z'] = 'some value';:

function set(&$array, $path, $value) {
//$path = explode('.', $path); //if needed
$path = "['" . implode("']['", $path) . "']";
eval("\$array{$path} = $value;");
}

Unsets something like $array['b']['x']['z']:

function unsetter(&$array, $path) {
//$path = explode('.', $path); //if needed
$path = "['" . implode("']['", $path) . "']";
eval("unset(\$array{$path});");
}

PHP get value from armultidimensional array based on array with keys

Try this approach:

$arr = [
"something" => [
'something_else' => [
"another_thing" => "boo"
]
],
"something2" => [
'something_elseghf' => [
"another_thingfg" => [
"hi" => "bye"
]
]
],
"info" => [
'something_else2' => [
"another_thingh" => "boo"
]
],
];

$keyArr = ["something2", 'something_elseghf', "another_thingfg", "hi"];


$cursor = $arr;
foreach ($keyArr as $key) {
$cursor = $cursor[$key];
}

echo $cursor;

Will echo

bye

UPDATE:

If you want to change a value within multi-dimentional array, then use a recursive function, like this:

function changeValue($array, $path, $value) {
if (empty($path)) {
return $value;
}
$key = array_shift($path);
$array[$key] = changeValue($array[$key], $path, $value);
return $array;
}

$arr = [
"something" => [
'something_else' => [
"another_thing" => "boo"
]
],
"something2" => [
'something_elseghf' => [
"another_thingfg" => [
"hi" => "bye"
]
]
],
"info" => [
'something_else2' => [
"another_thingh" => "boo"
]
],
];

$keyArr = ["something2", 'something_elseghf', "another_thingfg", "hi"];

$changedArray = changeValue($arr, $keyArr, 'New value!');

print_r($changedArray);

Will output

Array
(
[something] => Array
(
[something_else] => Array
(
[another_thing] => boo
)

)

[something2] => Array
(
[something_elseghf] => Array
(
[another_thingfg] => Array
(
[hi] => New value!
)

)

)

[info] => Array
(
[something_else2] => Array


(
[another_thingh] => boo
)

)
)

Unset element in multi-dimensional array by path

  $testArr = [
"globals" => [
"connects" => [
'setting1' => [
'test' => 'testCon1',
],
'setting2' => [
'abc' => 'testCon2',
],
],
],
'someOtherKey' => [],
];

$pathToUnset = "globals.connects.setting2";

function unsetByPath(&$array, $path) {
$path = explode('.', $path);
$temp = & $array;

foreach($path as $key) {
if(isset($temp[$key])){
if(!($key == end($path))) $temp = &$temp[$key];
} else {
return false; //invalid path
}
}
unset($temp[end($path)]);
}

unsetByPath($testArr, $pathToUnset);

PHP: Grab array value using an array of keys OR Reference array value using multiple variable keys

So you want to look for a value on an array where you know the path to?

Had the same thing, build me something.

Its not perfect. But it does the job.

Note: if you change it then do not return false if path not found. Because false could be a found value too.

The method:

/**
* Returns a value from given source by following the given keys.
*
* Example:
* <code>
* $array = [
* 'foo' => [
* 'bar' => [
* 'baz' => null,
* ],
* 'bar_2' => [
* 0 => [
* 'baz' => null,
* ],
* 1 => [
* 'baz' => 123,
* ],
* 2 => [
* 'baz' => 456,
* ],
* ]
* ]
* ];
* ::find($array, ['foo', 'bar_2', 1, 'baz']) // 123
* </code>
*
* @param array $source
* @param array $keys
*
* @return array|bool|mixed
*/
public function find(array $source, array $keys)
{
if (empty($keys)) {
// No keys - so actually expect the complete source to return.
return $source;
}
// Get the (next-) first key.
$keyCurrent = array_shift($keys);
if (!array_key_exists($keyCurrent, $source)) {
// Expected path to value does not exist.
throw new \InvalidArgumentException("Key '{$keyCurrent}' not found.");
}
$source = $source[$keyCurrent];
if (!empty($keys)) {
// Still got keys - need to keep looking for the value ...
if (!is_array($source)) {
// but no more array - cannot continue.
// Expected path to value does not exist. Return false.
throw new \InvalidArgumentException("No array on key '{$keyCurrent}'.");
}
// continue the search recursively.
$source = $this->find($source, $keys);
}
// No more keys to search for.
// We found the value on the given path.
return $source;
}

The test:

$array = [
'a' => ['id' => 'something at array[a][id]'],
'b' => ['id' => 'something at array[b][id]'],
'c' => [
'ca' => [
'cb' => [
'cc' => ['id' => 'something at array[c][ca][cb][cc][id]'],
],
],
],
];

$value = $this->find($array, ['c', 'ca', 'cb', 'cc', 'id']);
// something at array[c][ca][cb][cc][id]

$value = $this->find($array, ['c', 'ca', 'cb', 'cc']);
// array (
// 'id' => 'something at array[c][ca][cb][cc][id]',
// )

$value = $this->find($array, ['b', 'id']);
// something at array[b][id]

$value = $this->find($array, ['c', 'ca', 'cb', 'cc', 'does_not_exist']);
// Fatal error: Uncaught InvalidArgumentException: Key 'does_not_exist' not found. in

Defining values to specific indexes of a multidimensional array

could something like this be okay?

I only ask you to study this code not to implement it, for the simple reason that in the future you may have the same type of problem.


function setValue($key,$value,&$array){
$find_parts = explode(".", $key);
$find = $find_parts[0]??null;
if ($find!=null){
if ($find == "*"){
array_shift($find_parts);
foreach($array as &$sub_array){
setValue(implode(".",$find_parts),$value,$sub_array);
}
}else{
if (count($find_parts)>1){
if (array_key_exists($find,$array)){
array_shift($find_parts);
setValue(implode(".",$find_parts),$value,$array[$find]);
}
}else{
if (array_key_exists($find,$array)){
$array[$find] = $value;
}
}
}
}
}

function defineNewValues(&$arr, $keys) {
foreach($keys as $key=>$value){
setValue($key,$value,$arr);
}
}

$myArray=[
"data"=>[
"a"=>[
"content"=>[
"aa"=>[
"price" => 3,
"profit" => 2,
"other" => 1
],
"ab"=>[
"price" => 3,
"profit" => 2,
"other" => 2
]
]
],
"b"=>[
"content"=>[
"ba"=>[
"price" => 3,
"profit" => 2,
"other" => 4
],
"bb"=>[
"price" => 3,
"profit" => 2,
"other" => 5
]
]
],
]
];

defineNewValues($myArray, [
"data.*.content.*.price" => 0,
"data.*.content.*.profit" => 0,
]);

print_r($myArray);

/* OUTPUT
Array
(
[data] => Array
(
[a] => Array
(
[content] => Array
(
[aa] => Array
(
[price] => 0
[profit] => 0
[other] => 1
)
[ab] => Array
(
[price] => 0
[profit] => 0
[other] => 2
)
)
)
[b] => Array
(
[content] => Array
(
[ba] => Array
(
[price] => 0
[profit] => 0
[other] => 4
)
[bb] => Array
(
[price] => 0
[profit] => 0
[other] => 5
)
)
)
)
)
*/


Related Topics



Leave a reply



Submit