Use Strings to Access (Potentially Large) Multidimensional Arrays

use strings to access (potentially large) multidimensional arrays

Considering $vars being your variables you would like to get one['one-one'] or two['two-two']['more'] from (Demo):

$vars = function($str) use ($vars)
{
$c = function($v, $w) {return $w ? $v[$w] : $v;};
return array_reduce(preg_split('~\[\'|\'\]~', $str), $c, $vars);
};
echo $vars("one['one-one']"); # hello
echo $vars("two['two-two']['more']"); # tea-time!

This is lexing the string into key tokens and then traverse the $vars array on the keyed values while the $vars array has been turned into a function.


Older Stuff:

Overload the array with a function that just eval's:

$vars = array(
'one' => array(
'one-one' => "hello",
'one-two' => "goodbye"
),
'two' => array(
'two-one' => "foo",
'two-two' => "bar"
)
);

$vars = function($str) use ($vars)
{
return eval('return $vars'.$str.';');
};

echo $vars("['one']['one-two']"); # goodbye

If you're not a fan of eval, change the implementation:

$vars = function($str) use ($vars)
{
$r = preg_match_all('~\[\'([a-z-]+)\']~', $str, $keys);
$var = $vars;
foreach($keys[1] as $key)
$var = $var[$key];
return $var;
};
echo $vars("['one']['one-two']"); # goodbye

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
)

)
)

PHP: Use array to get value in another, multidimensional array

You might want to create some kind of helper function, where you iterate over parts of your path while keeping track of your temporary result:

function deep_array_get(array $path, array $subject) {

$result = $subject;
foreach ($path as $p) {
$result = $result[$p];
}

return $result;

}

Example:

$p = ["a", "b", "c"];
$s = [1, 2, "a" => [3, 4, "b" => ["c" => 5]]];
var_dump(deep_array_get($p, $s));

// Result: int(5)

In your exact usecase it would be used something like this:

$path = ['neighborhood', 'street', 'house'];
$subject = get_option($options_id);

$result = deep_array_get($path, $subject);

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});");
}

How to access a multidimensinal PHP array, when path (level) to value is dynamic changing?

Here's a small class I wrote that would determine the number of dimensions. You could easily modify it to do whatever you wanted, or just use the number it returns to guide your own function:

class DimensionCounter {

var $i;

public function count($array) {
$this->i = 1;
return $this->readArray($array);
}

private function readArray($array) {

foreach($array as $value) {
if (is_array($value)) {
$this->i++;
$this->readArray($value);
}
return $this->i;
}
}
}

In your case, $counter = new DimensionCounter(); $num = $counter->count($value); would give you the number of dimensions.

How to create a C++ multidimensional array of names with basic types

You can, e.g., get an array of pointers to null-terminated strings:

const char* names_array[] = { "Bob", "Carl" };

and then

std::printf("%s", names_array[0]);
std::printf("%s", names_array[1]);

The problem with your attempt

char names_array[2] = {"Bob","Carl"};

is that you declare names_array to be an array of characters. This should never compile because what the = {"Bob","Carl"} essentially attempts to do is initialize each character in that array of characters with an entire array of characters of its own. A character is just a character, you cannot assign an entire array of characters to just an individual character. More precisely, initialization of a character array from a string literal is a special case of initialization [dcl.init.string] that allows a single string literal to be used to initialize an entire character array (because anything else doesn't make sense). What you actually want would be something more like an array of character arrays. However, the problem there is that you'd have to effectively pick a fixed maximum length for all strings in the array:

char names_array[][5] = { "Bob", "Carl" };  // each subarray is 5 characters in length

which would be potentially wasteful. You can flatten a series of multiple strings into one long array and then index into that, like you did with your first approach. The downside of that, as you've found out, is that you then need to know where each string starts in that array…

If you just want an array of string constants, a more modern C++ approach would be something like this:

#include <string_view>

using namespace std::literals;

constexpr std::string_view names[] = {
"Bob"sv,
"Carl"sv
};

The advantage of std::string_view is that it also has information about the length of the string. However, while std::string_view is compatible with most of the C++ standard library facilities that handle strings, it's not so simple to use it together with functions that expect C-style null-terminated strings. If you need null-terminated strings, I'd suggest to simply use an array of pointers to strings as shown at the very beginning of this answer…



Related Topics



Leave a reply



Submit