动态访问多维数组的值

7

我希望找到(或创建)一个函数。我有一个多维数组:

$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"
    ]
];

我想使用单维数组访问一个值,像这样:

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

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

这似乎已经有了一个用于此类事情的函数,我只是不知道该搜索什么。


你是指访问 $data_arr['a']['ab']['abc'] 吗? - Fabian N.
1
没错...它会将['a', 'ab', 'abc']转换为$data_arr['a']['ab']['abc'] - Phil Tune
4个回答

9

试试这个

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

    return $current;
}

OP的解释:

$current变量会不断地被构建,具体如下:

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'];

在每个迭代中您也可以执行 if ( isset($current) ) ... 以提供错误检查。

缺少$key,它从哪里获取?哦,我想你是指$data_arr_call as $key - Phil Tune
2
虽然这段代码片段可能解决了问题,但包括解释真的有助于提高您的帖子质量。请记住,您正在为未来的读者回答问题,而这些人可能不知道您的代码建议原因。请尽量不要在代码中添加过多的解释性注释,这会降低代码和解释的可读性! - Rizier123
1
是的,我弄明白为什么这样可以了,但就像@Rizier123说的那样,你应该写个解释,我会接受这个答案。谢谢。 - Phil Tune
@LibertyPaul 对于一些用户来说,这可能很简单,但对于其他人来说并非如此。通过添加更多的解释,未来的读者可以更好地理解它。 - Rizier123
是的,我同意...就像我说的,我弄清楚了它为什么会这样做,但我花了一分钟才想明白...解释有助于理解。我会写一个编辑。 - Phil Tune
显示剩余4条评论

4
您可以使用此函数,它避免了整个数组的复制(使用引用),能够返回NULL值(使用array_key_exists而不是isset),并在路径不存在时抛出异常:
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;
}

演示:

$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"]

请注意,这个函数可以改进,例如您可以测试参数是否为数组。

是的!这是一个更负责任的解决方案,传递下一次迭代的引用,而不是每一步旅程的副本。这样做更加节约资源,性能也显著提高。 - undefined

3

希望提供一个更加优雅的解决方案:array_reduce

最初的回答
    $data_arr = [
        "a" => [
            ...
            "ab" => [
                ...
                "abc" => "abcfoo"
            ],
            ...
        ],
        ...
    ];

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

    // returns "abcfoo"

最近我一直在使用JavaScript的Array.reduce()来更新一些遗留代码到ES6:

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

0
你需要这样的一个函数:
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;
}

然后像这样使用它:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接