在PHP中创建动态分层数组

时间:2016-08-04 04:26:37

标签: php arrays

我有这个通用的数据结构:

$levels = array('country', 'state', 'city', 'location');

我的数据如下:

$locations = array(
  1 => array('country'=>'USA', 'state'=>'New York', 'city'=>'NYC', 'location'=>'Central Park', 'count'=>123),
  2 => array('country'=>'Germany', ... )
);

我想创建分层数组,例如

$hierarchy = array(
  'USA' => array(
    'New York' => array(
      'NYC' => array(
        'Central Park' => 123,
      ),
    ),
  ),
  'Germany' => array(...),
);

通常我会像这样创建它:

$final = array();
foreach ($locations as $L) {
    $final[$L['country']][$L['state']][$L['city']][$L['location']] = $L['count'];
}

然而,事实证明,初始数组$ level是动态的,可以改变值和长度所以我不能将级别硬编码到最后一行,我不知道有多少元素。因此$ levels数组可能如下所示:

$levels = array('country', 'state');

$levels = array('country', 'state', 'location');

值将始终存在于要处理的数据中,但处理数据中的元素可能多于级别数组中的元素。我希望最终数组只包含$ levels数组中的值,无论原始数据中有什么附加值。

如何使用数组$ levels作为动态创建$ final数组的指导?

我以为我可以使用implode()构建字符串$final[$L['country']][$L['state']][$L['city']][$L['location']],然后在其上运行eval(),但是有更好的方法吗?

5 个答案:

答案 0 :(得分:2)

这是我的实施。您可以尝试here

$locations = array(
  1 => array('country'=>'USA', 'state'=>'New York', 'city'=>'NYC', 'location'=>'Central Park', 'count'=>123),
  2 => array('country'=>'Germany', 'state'=>'Blah', 'city'=>'NY', 'location'=>'Testing', 'count'=>54),
);

$hierarchy = array();

$levels = array_reverse(
    array('country', 'state', 'city', 'location')
);

$lastLevel = 'count';


foreach ( $locations as $L )
{
    $array = $L[$lastLevel];

    foreach ( $levels as $level )
    {
        $array = array($L[$level] => $array);
    }

    $hierarchy = array_merge_recursive($hierarchy, $array);
}

print_r($hierarchy);

答案 1 :(得分:2)

很酷的问题。一个简单的方法:

$output = []; //will hold what you want
foreach($locations as $loc){
    $str_to_eval='$output';
    for($i=0;$i<count($levels);$i++) $str_to_eval .= "[\$loc[\$levels[$i]]]";
    $str_to_eval .= "=\$loc['count'];";
    eval($str_to_eval); //will build the array for this location
}

Live demo

答案 2 :(得分:0)

如果您的数据集始终采用固定结构,则可以将其循环

$data[] = [country=>usa, state=>ny, city=>...]

to
foreach ($data as $row) {
    $result[][$row[country]][$row[state]][$row[city]] = ...
}

如果您的数据是动态的并且嵌套数组的级别也是动态的,那么以下是一个想法:

/* convert from [a, b, c, d, ...] to [a][b][...] = ... */

function nested_array($rows, $level = 1) {
    $data = array();
    $keys = array_slice(array_keys($rows[0]), 0, $level);
    foreach ($rows as $r) {
        $ref = &$data[$r[$keys[0]]];
        foreach ($keys as $j => $k) {
            if ($j) {
                $ref = &$ref[$r[$k]];
            }
            unset($r[$k]);
        }
        $ref = count($r) > 1 ? $r : reset($r);
    }
    return $data;
}

答案 3 :(得分:0)

试试这个:

<?php
$locations = [
    ['country'=>'USA', 'state'=>'New York', 'city'=>'NYC', 'location'=>'Central Park', 'street'=>'7th Ave',  'count'=>123],
    ['country'=>'USA', 'state'=>'Maryland', 'city'=>'Baltimore', 'location'=>'Harbor', 'count'=>24],
    ['country'=>'USA', 'state'=>'Michigan', 'city'=>'Lansing', 'location'=>'Midtown', 'building'=>'H2B', 'count'=>7],
    ['country'=>'France', 'state'=>'Sud', 'city'=>'Marseille', 'location'=>'Centre Ville', 'count'=>12],
];

$nk = array();
foreach($locations as $l) {
    $jsonstr = json_encode($l);
    preg_match_all('/"[a-z]+?":/',$jsonstr,$e);

    $narr = array();
    foreach($e[0] as $k => $v) {
        if($k == 0 ) {
            $narr[] = '';
        } else {
            $narr[] = ":{";
        }        
    }
    $narr[count($e[0]) -1] = ":" ;
    $narr[] = "";
    $e[0][] = ",";

    $jsonstr = str_replace($e[0],$narr,$jsonstr).str_repeat("}",count($narr)-3);

    $nk [] = $ko =json_decode($jsonstr,TRUE);

}
print_r($nk);

答案 4 :(得分:-1)

数据库有三个字段: 这里名称conatin contry州和城市名称

id,name,parentid

将contry结果传递给数组以下函数:

$data['contry']=$this->db->get('contry')->result_array();
$return['result']=$this->ordered_menu( $data['contry'],0);
echo "<pre>";
     print_r ($return['result']);
     echo "</pre>";


  Create Function as below:

function ordered_menu($array,$parent_id = 0)
    { 
        $temp_array = array();
        foreach($array as $element)
        {
            if($element['parent_id']==$parent_id)
            {
                $element['subs'] = $this->ordered_menu($array,$element['id']);
                $temp_array[] = $element;
            }
        }
        return $temp_array;
    }