7

I'm trying to find (or create) a function. I have a multidimensional array:

$data_arr = [
    "a" => [
        "aa" => "abfoo",
        "ab" => [
            "aba" => "abafoo",
            "abb" => "abbfoo",
            "abc" => "abcfoo"
        ],
        "ac" => "acfoo"
    ],
    "b" => [
        "ba" => "bafoo",
        "bb" => "bbfoo",
        "bc" => "bcfoo"
    ],
    "c" => [
        "ca" => "cafoo",
        "cb" => "cbfoo",
        "cc" => "ccfoo"
    ]
];

And I want to access a value using a single-dimentional array, like this:

$data_arr_call = ["a", "ab", "abc"];

someFunction( $data_arr, $data_arr_call ); // should return "abcfoo"

This seems like there's probably already a function for this type of thing, I just don't know what to search for.

2
  • Do you mean accessing $data_arr['a']['ab']['abc']? Commented Mar 31, 2016 at 13:21
  • 1
    Right... it would pretty much take ['a', 'ab', 'abc'] and recognize that it means $data_arr['a']['ab']['abc'] Commented Mar 31, 2016 at 13:22

4 Answers 4

9

Try this

function flatCall($data_arr, $data_arr_call){
    $current = $data_arr;
    foreach($data_arr_call as $key){
        $current = $current[$key];
    }

    return $current;
}

OP's Explanation:

The $current variable gets iteratively built up, like so:

flatCall($data_arr, ['a','ab','abc']);

1st iteration: $current = $data_arr['a'];
2nd iteration: $current = $data_arr['a']['ab'];
3rd iteration: $current = $data_arr['a']['ab']['abc'];

You could also do if ( isset($current) ) ... in each iteration to provide an error-check.

Sign up to request clarification or add additional context in comments.

9 Comments

missing $key, where is it pulling that? Oh, I think you mean $data_arr_call as $key
@philtune yes, excactly
While this code snippet may solve the question, including an explanation really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. Please also try not to crowd your code with explanatory comments, this reduces the readability of both the code and the explanations!
Yeah, I figured out why that works, but like @Rizier123 said, you should write up an explanation and I will accept this answer. Thanks.
@Rizier123 I'm sure that those 3 simple lines of code doesn't need any explanation. If you aren't agree with that you may do it yourself.
|
4

You can use this function that avoids the copy of the whole array (using references), is able to return a NULL value (using array_key_exists instead of isset), and that throws an exception when the path doesn't exist:

function getItem(&$array, $path) {
    $target = &$array;
    foreach($path as $key) {
        if (array_key_exists($key, $target))
            $target = &$target[$key];
        else throw new Exception('Undefined path: ["' . implode('","', $path) . '"]');
    }
    return $target;
}

demo:

$data = [
    "a" => [
        "aa" => "abfoo",
        "ab" => [
            "aba" => "abafoo",
            "abb" => NULL,
            "abc" => false
        ]
    ]
];

var_dump(getItem($data, ['a', 'ab', 'aba']));
# string(6) "abafoo"
var_dump(getItem($data, ['a', 'ab', 'abb']));
# NULL
var_dump(getItem($data, ['a', 'ab', 'abc']));
# bool(false)
try {
    getItem($data, ['a', 'ab', 'abe']);
} catch(Exception $e) {
    echo $e->getMessage();
}
# Undefined path: ["a","ab","abe"]

Note that this function can be improved, for example you can test if the parameters are arrays.

1 Comment

Yes! This is a much more responsible solution, passing a reference to the next iteration, instead of a copy of each step in the journey. Far less wasteful, and significantly more performant, it would seem.
3

Wanted to post an even more elegant solution: array_reduce

    $data_arr = [
        "a" => [
            ...
            "ab" => [
                ...
                "abc" => "abcfoo"
            ],
            ...
        ],
        ...
    ];

    $result = array_reduce(["a", "ab", "abc"], function($a, $b) {
        return $a[$b];
    }, $data_arr);

    // returns "abcfoo"

I've been using Javascript's Array.reduce() a lot lately in updating some legacy code to ES6:

JS:
const data_obj = {...};
let result = ['a','ab','abc'].reduce((a, b) => a[b], data_obj);

Comments

0

You need a function like this:

function getValue($data_arr, $data_arr_call) {
    foreach ($data_arr_call as $index) {
        if (isset($data_arr[$index])) {
            $data_arr = $data_arr[$index];
        } else {
            return false;
        }
    }
    return $data_arr;
}

And use it like this:

$data_arr = [
    "a" => [
        "ab" => [
            "abc" => "abbfoo",
        ],
    ],
];
$data_arr_call = ["a", "ab", "abc"];
$value = getValue($data_arr, $data_arr_call);
if ($value) {
    // do your stuff
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.