Как использовать строку в качестве пути индекса массива для получения значения?

скажем, у меня есть массив, например:

Array
(
    [0] => Array
        (
            [Data] => Array
                (
                    [id] => 1
                    [title] => Manager
                    [name] => John Smith
                )
         )
    [1] => Array
        (
            [Data] => Array
                 (
                     [id] => 1
                     [title] => Clerk
                     [name] =>
                         (
                             [first] => Jane
                             [last] => Smith
                         )
                 )

        )

)

Я хочу иметь возможность построить функцию, которую я могу передать строку, которая будет действовать как путь индекса массива и возвращать соответствующее значение массива без использования eval(). Это возможно?

function($indexPath, $arrayToAccess)
{
    // $indexPath would be something like [0]['Data']['name'] which would return 
    // "Manager" or it could be [1]['Data']['name']['first'] which would return 
    // "Jane" but the amount of array indexes that will be in the index path can 
    // change, so there might be 3 like the first example, or 4 like the second.

    return $arrayToAccess[$indexPath] // <- obviously won't work
}

10 ответов


вы можете использовать массив как путь (слева направо), а затем рекурсивную функцию:

$indexes = {0, 'Data', 'name'};

function get_value($indexes, $arrayToAccess)
{
   if(count($indexes) > 1) 
    return get_value(array_slice($indexes, 1), $arrayToAccess[$indexes[0]]);
   else
    return $arrayToAccess[$indexes[0]];
}

немного позже, но... надежда помогает кому-то:

// $pathStr = "an:string:with:many:keys:as:path";
$paths = explode(":", $pathStr); 
$itens = $myArray;
foreach($paths as $ndx){
    $itens = $itens[$ndx];
}

теперь itens является частью массива, который вы хотели.

[] ' s

Labs


Это старый вопрос, но на него ссылались, поскольку этот вопрос возникает часто.

есть рекурсивные функции, но я использую ссылку:

function array_nested_value($array, $path) {
    $temp = &$array;

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

$path  = array(0, 'Data', 'Name');
$value = array_nested_value($array, $path);

попробуйте следующее, где $indexPath отформатирован как путь к файлу, т. е.

'<array_key1>/<array_key2>/<array_key3>/...'.

function($indexPath, $arrayToAccess)
{
    $explodedPath = explode('/', $indexPath);
    $value =& $arrayToAccess;
    foreach ($explodedPath as $key) {
        $value =& $value[$key];
    }
    return $value;
}

например, используя данные из вопроса, $indexPath = '1/Data/name / first' вернет $value = Jane.


function($indexPath, $arrayToAccess)
{
    eval('$return=$arrayToAccess'.$indexPath.';');
    return $return;
}

вы должны проанализировать строку indexPath. Выберите какой-нибудь разделитель (например "."), читать текст до ".- это будет первый ключ, потом читай "отдых до следующего", это будет следующий ключ. Делайте это до тех пор, пока не будет больше точек.

вы Кен храните ключ в массиве. Сделайте цикл foreach в этом массиве, чтобы получить элемент seeked.


вот один из способов выполнить работу, если синтаксический анализ строк-это то, как вы хотите пойти.

$data[0]["Data"]["stuff"] = "cake";

$path = "[0][\"Data\"]['stuff']";

function indexPath($path,$array){
    preg_match_all("/\[['\"]*([a-z0-9_-]+)['\"]*\]/i",$path,$matches);

    if(count($matches[1]) > 0) {
        foreach ($matches[1] as $key) {
                if (isset($array[$key])) {
                        $array = $array[$key];
                } else {
                        return false;
                }
        }
    } else {
        return false;
    }

return $array;
}

print_r(indexPath($path,$data));

на preg_match_all, велоспорт через сопоставленные результаты даст вам близко к результату, который вы хотели. Вы должны быть осторожны со всеми стратегиями, перечисленными здесь потерянную информацию. Например, вы должны придумать какой-то способ убедиться, что 55 остается как тип int и не анализируется как строка типа.


В дополнение к AbraCadaver:

function array_nested_value($array, $path) {

    foreach($path as $key) {

        $array = $array[$key];
    }

    return $array;
}

$path  = array(0, 'Data', 'Name');
$value = array_nested_value($array, $path);

можно использовать

function get_array_value($array=array(), $path=array()){

    foreach($path as $key) {

        if(isset($array[$key])){

            $array=$array[$key];
        }
        else{

            $array=NULL;
            break;
        }
    }

    return $array;
}

function custom_isset($array=array(), $path=array()){

    $isset=true;

    if(is_array($array)&&is_null(get_array_value($array, $path))){

        $isset=false;
    }

    return $isset;
}

function is($array=array(), $path=array()){

    $is=false;

    if(is_array($array)){

        $array_value=get_array_value($array, $path);

        if(is_bool($array_value)){

            $is=$array_value;
        }
    }

    return $is;
}

пример

    $status=[];

    $status['updated']=true;

        if(is($status,array('updated'))){

                //do something...

        }

ресурсы

https://gist.github.com/rafasashi/0d3ebadf08b8c2976a9d


Если вы уже знаете точный элемент массива, который вы вытаскиваете, зачем писать функцию для этого? Что случилось с just

$array[0]['data']['title']