如何使用其键将数组分组为子数组?

时间:2017-01-10 12:30:05

标签: php arrays json optimization multidimensional-array

我希望根据其键将数组分组到子数组中。

示例数组

10/1/2017 12:52

我需要将此示例数组转换为以下格式的JSON数组:

预期输出

Array
(
    [0] => Array
        (
            [a_id] => 1
            [a_name] => A1
            [b_id] => 1
            [b_name] => B1
            [c_id] => 1
            [c_name] => C1
        )

    [1] => Array
        (
            [a_id] => 1
            [a_name] => A1
            [b_id] => 1
            [b_name] => B1
            [c_id] => 2
            [c_name] => C2
        )

    [2] => Array
        (
            [a_id] => 1
            [a_name] => A1
            [b_id] => 2
            [b_name] => B2
            [c_id] => 3
            [c_name] => C3
        )

    [3] => Array
        (
            [a_id] => 2
            [a_name] => A2
            [b_id] => 3
            [b_name] => B3
            [c_id] => 4
            [c_name] => C4
        )

)

我可以使用下面的代码按键分组。

[{
    "a_id": 1,
    "a_name": "A1",
    "b_list": [{
        "b_id": 1,
        "b_name": "B1",
        "c_list": [{
            "c_id": 1,
            "c_name": "C1"
        }, {
            "c_id": 2,
            "c_name": "C2"
        }]
    }, {
        "b_id": 2,
        "b_name": "B2",
        "c_list": [{
            "c_id": 3,
            "c_name": "C3"
        }]
    }]
}, {
    "a_id": 2,
    "a_name": "A2",
    "b_list": [{
        "b_id": 3,
        "b_name": "B3",
        "c_list": [{
            "c_id": 4,
            "c_name": "C4"
        }]
    }]
}]

但是我的实际情况涉及分组到子数组中没有用。

期待看看是否有优化的方法或有用的功能来进入我期望的JSON响应。

注意:我在这里研究一个通用用例。例如:$array = array( array("a_id" => "1","a_name" => "A1","b_id" => "1","b_name" => "B1","c_id" => "1","c_name" => "C1"), array("a_id" => "1","a_name" => "A1","b_id" => "1","b_name" => "B1","c_id" => "2","c_name" => "C2"), array("a_id" => "1","a_name" => "A1","b_id" => "2","b_name" => "B2","c_id" => "3","c_name" => "C3"), array("a_id" => "2","a_name" => "A2","b_id" => "3","b_name" => "B3","c_id" => "4","c_name" => "C4") ); $return = array(); foreach($array as $val) { $return[$val["a_id"]][] = $val; } print_r($return); 为国家/地区,a_list为州,b_list为城市。

6 个答案:

答案 0 :(得分:2)

man是数组的非常具体的用例。那么这是你的解决方案。

$array = <YOUR SAMPLE ARRAY>
$output = [];
/*
 * Nesting array based on a_id, b_id
 */
foreach ($array as $item) {
    $aid = $item['a_id'];
    $bid = $item['b_id'];
    $cid = $item['c_id'];
    if(!isset($output[$aid])){
        $output[$aid] = [
            'a_id' => $item['a_id'],
            'a_name' => $item['a_name'],
            'b_list' => [
                $bid => [
                    'b_id' => $item['b_id'],
                    'b_name' => $item['b_name'],
                    'c_list' => [
                        $cid = [
                            'c_id' => $item['c_id'],
                            'c_name' => $item['c_name']
                        ]
                    ]
                ]
            ]
        ];
    } else if (!isset($output[$aid]['b_list'][$bid])){
        $output[$aid]['b_list'][$bid] =  [
            'b_id' => $item['b_id'],
            'b_name' => $item['b_name'],
            'c_list' => [
                $cid => [
                    'c_id' => $item['c_id'],
                    'c_name' => $item['c_name']
                ]
            ]
        ];
    } else if(!isset($output[$aid]['b_list'][$bid]['c_list'][$cid])) {
        $output[$aid]['b_list'][$bid]['c_list'][$cid] = [
            'c_id' => $item['c_id'],
            'c_name' => $item['c_name']
        ];
    } else {
        // Do/Dont overrider
    }
}
/*
 * Removing the associativity from the b_list and c_list
 */
function indexed($input){

    $output = [];
    foreach ($input as $key => $item) {
        if(is_array($item)){
            if($key == 'b_list' || $key == 'c_list'){
                $output[$key] = indexed($item);
            } else {
                $output[] = indexed($item);
            }
        } else {
            $output[$key] = $item;
        }
    }
    return $output;
}
$indexed = indexed($output);
print_r(json_encode($indexed, 128));

答案 1 :(得分:2)

那里有趣的要求。 这是我的可扩展的通用解决方案。

function transform($array, $group=[
    ['a_id','a_name','b_list'],
    ['b_id','b_name','c_list'],
    ['c_id','c_name'],
]){
    foreach($array as $a){
        $r = &$result;
        foreach($group as $g){
            $x = &$r[$a[$g[0]]];
            $x[$g[0]] = $a[$g[0]];
            $x[$g[1]] = $a[$g[1]];
            if(isset($g[2])) $r = &$x[$g[2]]; else break;
        }
    }
    return transformResult($result);
}

function transformResult($result){
    foreach($result as &$a)
        foreach($a as &$b)
            if(is_array($b)) $b = transformResult($b);
    return array_values($result);
}

要扩展此解决方案,您所要做的就是修改$group参数, 直接在函数声明中或通过传递适当的值作为第二个参数。

用法示例:

echo json_encode(transform($array), JSON_PRETTY_PRINT);

假设示例中的$array输入相同,这将返回相同的输出。

答案 2 :(得分:2)

现在,这是在给定情况下效果最佳的代码。我创建了类似的情况,然后详细解释了解决方案。

<强>场合
订单表格是多页的,具体取决于所选包裹的天数。每个包的详细信息都存储在数据库中,包含以下字段:

  1. package_id(唯一字段)
  2. package_name(包名称,例如包A)
  3. servings_count(一天的总份量)
  4. days_served(一个月内服务的天数)
  5. 为了将每天的膳食选择和当天的服务作为订单存储在数据库中,我需要一个可以动态定义/填充的多维PHP数组。

    预期输出类似于:

    Array
    (
        [Day 1] => Array
            (
                [meal_id_1] => Unique ID //to be replaced with user selection
                [meal_code_1] => Meal Name //to be replaced with user selection
                [meal_type_1] => Meal //prefilled based on the selected package
                [meal_id_2] => Not Available //to be replaced with user selection
                [meal_code_2] => 2 //to be replaced with user selection
                [meal_type_2] => Meal //prefilled based on the selected package
            )
    
        [Day 2] => Array
            (
                [meal_id_1] => Unique ID //to be replaced with user selection
                [meal_code_1] => Meal Name //to be replaced with user selection
                [meal_type_1] => Meal //prefilled based on the selected package
                [meal_id_2] => Not Available //to be replaced with user selection
                [meal_code_2] => 2 //to be replaced with user selection
                [meal_type_2] => Meal //prefilled based on the selected package
            )
    

    以上数组是根据所解释的结构,份数和天数动态创建的。下面是代码并做了一些解释。

    首先,我们必须声明两个PHP数组。

    $total_meals_array = []; //Primary, Multidimension Array
    $meals_selected_array = []; //Meals Details Array to be used as primary array's key value.
    

    执行此操作后,运行MySQL查询以从数据库中读取包。现在根据结果,执行以下操作:

    $total_meals_array = []; //Primary, Multidimension Array
    $meals_selected_array = []; //Meals Details Array to be used as primary array's key value.
    
    if( $num_row_packages >= 1 ) {
        while($row_packages = mysqli_fetch_array ($result_packages)) {
            $package_id = $row_packages['package_id'];
            $package_name = $row_packages['package_name'];
            $servings_count = $row_packages['servings_count'];
            $days_served = $row_packages['days_served'];
    
            //this for loop is to repeat the code inside `$days_served` number of times. This will be defining our primary and main Multidimensional Array `$total_meals_array`.
            for ($y = 1; $y <= $days_served; $y++) {
                //once inside the code, now is the time to define/populate our secondary array that will be used as primary array's key value. `$i`, which is the meal count of each day, will be added to the key name to make it easier to read it later. This will be repeated `$meals_count` times.
    
                for ($i = 1; $i <= $meals_count; $i++) {
                    $meals_selected_array["meal_id_" . $i] = "Unique ID";
                    $meals_selected_array["meal_code_" . $i] = "Meal Name";
                    $meals_selected_array["meal_type_" . $i] = "Meal";
                }
    
                //once our secondary array, which will be used as the primary array's key value, is ready, we will start defining/populating our Primary Multidimensional Array with Keys Named based on `$days_served`.
                $total_meals_array["Day " . $y] = $meals_selected_array;
            }
        }
    }
    

    就是这样!我们的动态多维数组已经准备就绪,可以通过以下代码查看:

    print "<pre>";
    print_r($total_meals_array);
    print "</pre>";
    

    谢谢大家,特别是@yarwest,我很友好地回答了我的问题。

答案 3 :(得分:1)

这是代码,您可以将它用于从a_到y_深的索引。如果你不想要它,那么innerest元素为null。在最后一个元素之前终止for循环,然后单独处理最后一个元素。您也可以对此代码进行一些改进。希望这会有所帮助。

 <?php
    $array = array(
    array("a_id" => "1","a_name" => "A1","b_id" => "1","b_name" => "B1","c_id" => "1","c_name" => "C1"),
    array("a_id" => "1","a_name" => "A1","b_id" => "1","b_name" => "B1","c_id" => "2","c_name" => "C2"),
    array("a_id" => "1","a_name" => "A1","b_id" => "2","b_name" => "B2","c_id" => "3","c_name" => "C3"),
    array("a_id" => "2","a_name" => "A2","b_id" => "3","b_name" => "B3","c_id" => "4","c_name" => "C4")
    );
    $arrays = array_map(function($v){return array_chunk($v, 2, true);}, $array);
    $result = [];
    foreach($arrays as $value)
    {
        $ref = &$result;
        $len = count($value);
        $index = 0;
        for(; $index < $len; $index++)
        {
            $arr = $value[$index];
            $char = key($arr)[0];
            $charAdd = chr(ord($char)+1);
            $key = $arr[$char.'_id'].$arr[$char.'_name'];
            $listKey = $charAdd.'_list';
            foreach($arr as $k => $v)
            {
                $ref[$key][$k] = $v;
            }
            $ref = &$ref[$key][$listKey];
        }
    }
    var_dump($result);

输出:在线 live demo

ei@localhost:~$ php test.php
array(2) {
  ["1A1"]=>
  array(3) {
    ["a_id"]=>
    string(1) "1"
    ["a_name"]=>
    string(2) "A1"
    ["b_list"]=>
    array(2) {
      ["1B1"]=>
      array(3) {
        ["b_id"]=>
        string(1) "1"
        ["b_name"]=>
        string(2) "B1"
        ["c_list"]=>
        array(2) {
          ["1C1"]=>
          array(3) {
            ["c_id"]=>
            string(1) "1"
            ["c_name"]=>
            string(2) "C1"
            ["d_list"]=>
            NULL
          }
          ["2C2"]=>
          array(3) {
            ["c_id"]=>
            string(1) "2"
            ["c_name"]=>
            string(2) "C2"
            ["d_list"]=>
            NULL
          }
        }
      }
      ["2B2"]=>
      array(3) {
        ["b_id"]=>
        string(1) "2"
        ["b_name"]=>
        string(2) "B2"
        ["c_list"]=>
        array(1) {
          ["3C3"]=>
          array(3) {
            ["c_id"]=>
            string(1) "3"
            ["c_name"]=>
            string(2) "C3"
            ["d_list"]=>
            NULL
          }
        }
      }
    }
  }
  ["2A2"]=>
  array(3) {
    ["a_id"]=>
    string(1) "2"
    ["a_name"]=>
    string(2) "A2"
    ["b_list"]=>
    array(1) {
      ["3B3"]=>
      array(3) {
        ["b_id"]=>
        string(1) "3"
        ["b_name"]=>
        string(2) "B3"
        ["c_list"]=>
        array(1) {
          ["4C4"]=>
          array(3) {
            ["c_id"]=>
            string(1) "4"
            ["c_name"]=>
            string(2) "C4"
            ["d_list"]=>
            &NULL
          }
        }
      }
    }
  }
}

答案 4 :(得分:0)

这很有趣。据我所知,您正在尝试将平面数组转换为多维数组,以及将转换为多维表示。

顶级差异似乎位于a_*键下划线之前的部分。

然后,对于这些键中的每一个,每隔一个*_个字母都应该引出它自己的列表。

这种递归函数可以在没有硬编码的情况下完成,可以使用任意数量的级别,字母(或其他任何内容)和正确的标识符。

它似乎准确返回您在示例中显示的json($array是您问题中定义的数组)

$multidimension = multidimensionalify($array, ['a', 'b', 'c'], ['name']);
var_dump(json_encode($multidimension, JSON_PRETTY_PRINT));

function multidimensionalify(
    array $input,
    array $topLevelLetters,
    array $rightHandIdentifiers,
    $level = 0,
    $parentId = null,
    $uniqueString = 'id'
)
{
    $thisDimension = [];
    $thisLetter = $topLevelLetters[$level];
    foreach ($input as $entry)
    {
        $thisId = $entry["{$thisLetter}_{$uniqueString}"];
        $condition = true;
        if ($parentId !== null)
        {
            $parentLetter = $topLevelLetters[$level - 1];
            $condition = $entry["{$parentLetter}_{$uniqueString}"] === $parentId;
        }
        if (!isset($thisDimension[$thisId]) && $condition)
        {
            $thisObject = new stdClass;
            $thisObject->{"{$thisLetter}_{$uniqueString}"} = $thisId;
            foreach ($rightHandIdentifiers as $identifier)
            {
                $thisObject->{"{$thisLetter}_{$identifier}"} = $entry["{$thisLetter}_{$identifier}"];
            }
            if (isset($topLevelLetters[$level + 1])) {
                $nextLetter = $topLevelLetters[$level + 1];
                $thisObject->{"{$nextLetter}_list"} = multidimensionalify($input, $topLevelLetters, $rightHandIdentifiers, $level + 1, $thisId, $uniqueString);
            }
            $thisDimension[$thisId] = $thisObject;
        }
    }
    return array_values($thisDimension);
}

答案 5 :(得分:0)

尝试此函数只需传递数组和键名进行分组,然后转换为json。

public function _group_by($array, $key) {
    $return = array();
    foreach ($array as $val) {
        $return[$val[$key]][] = $val;
    }
    return $return;
}