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
Laravel - Page Not Found Even That the Route Exists
Finding the Longest Gap Between Multiple Intervals
Success Message Pop-Up After from Submit Button Clicked
Stop Inserting Data in the Database When Refreshing the Page
Displaying a Base64 Images from a Database Via PHP
Displaying Data from an Array in a HTML Table Using PHP
How to Get Values of Checkbox Array in Laravel 5
Convert Doc/Docx Files to Pdf Using PHP
How to Edit Specific Json Key Values Using PHP
Phpexcel Write Long Number in Cell
How to Check If a Row Exists in MySQL (I.E. Check If Username or Email Exists in MySQL)
Are Pdo Prepared Statements Sufficient to Prevent SQL Injection