【问题标题】:refactor multidimensional json in php by keys通过键在php中重构多维json
【发布时间】:2021-12-19 21:58:06
【问题描述】:

我正在做一个项目,我正在尝试通过 $keys 数组重构一个 json 对象 例如:

  1. 作为输入:
{
    "message": "User Detail",
    "code": 200,
    "error": false,
    "results": {
        "user": {
            "id": 2,
            "name": "ali",
            "country": {
                "id": 50,
                "name": "EGY"
            }
        },
        "access_token": "=PQLkHJYIXB2uKbCq4sXIjD2GpBU2o"
    }
}
  1. 作为输入:$keys 数组
$kyes = [
    'code',
    'user'=>[
        'id',
        'country'=>['name']
    ]
]

期待回归:

{
    "code": 200,
    "user": {
        "id": 2,
        "country": {
           "name": "egy",
        }
    }
}

我试过的代码:

    public function filter_multidimensional(array $array, array $keys){
        $val = [];
        foreach ($array as $key => $value) {
            if (in_array($key,$keys)){
                $val[$key] = $value;
            }elseif (is_array($value)) {
                $val[$key] = $this->filter_multidimensional($keys,$value);
            }
        }
        return $val;
    }
    //-------
    $this->filter_multidimensional($json,['code','user'=>['id','country'=>['name']]])

不幸的是输出:

更新 1

json 输入不是 const,所以我的代码必须适应。这就是我想要做的。

【问题讨论】:

    标签: php arrays json laravel


    【解决方案1】:

    感谢@404-not-found 他的代码很棒,但缺少一个小东西 在这段代码中

    if (is_array($key)) {
       $val[$objectKey] = filter_multidimensional($array, $key);
    }
    

    你仍然给 find 函数一个基本数组,它将返回它在 ['user'=>['id',"country"=>['id']]] 的情况下找到的第一个值,解决这个问题的方法是传递对象键的父数组

    所以完整的代码将是

    
    <?php
    
    function filter_multidimensional(array $array, array $keys) {
        if (empty($keys) || empty($array)) {
            return [];
        }
    
        $val = [];
        // In the structure of $keys, both key and value are technically "keys".
        // In the example `['code','user'=>['id']]`, 'code' and 'id' are both array *values*,
        // while 'user' is a key.
        //
        // So, $objectKey is a search key which contains sub-keys, while $key is just a regular string.
        foreach ($keys as $objectKey => $key) {
            // If $key is an array, then recursively search, and save the results to the $objectKey string.
            if (is_array($key)) {
    
                $val[$objectKey] = filter_multidimensional(findTill($array,$objectKey), $key);
            }
            // If the desired key exists, then save the value.
            else if (array_key_exists($key, $array)) {
                $val[$key] = $array[$key];
            }
            // Otherwise, $key is a string, but it does not exist at this level of $array,
            // so search the next-level up in $array, and merge the results into this level of $val.
            else {
                $val = array_merge($val, filter_multidimensional(nextLevel($array), [$key]));
            }
        }
    
        return $val;
    }
    
    
    function findTill($array,$key) {
        if (array_key_exists($key, $array)) {
            return $array[$key];
        }
        return findTill(nextLevel($array),$key);
    }
    
    /**
     * Create an array that contains only the array values from $array.
     *
     * Eg: If given ['a' => '1', 'b' => ['foo' => '2'], 'c' => ['hello' => 'world']],
     * then return ['foo' => '2', 'hello' => 'world']
     *
     * @param array $array
     * @return array
     */
    function nextLevel(array $array) {
        // Merge all of the array values together into one array
        return array_reduce(
        // Strip the keys
            array_values(
            // Filter to return only keys where the value is an array
                array_filter(
                    $array,
                    function ($value) {
                        return is_array($value);
                    }
                )
            ),
            'array_merge',
            []
        );
    }
    //-------
    
    $obj = [
        "message" => "User Detail",
        "code" => 200,
        "error" => false,
        "results" => [
            "user" => [
                "id" => 2,
                "name" => "ali",
                "country" => [
                    "id" => 50,
                    "name" => "EGY",
                ],
            ],
            "access_token" => "=PQLkHJYIXB2uKbCq4sXIjD2GpBU2o",
        ],
    ];
    
    $result = filter_multidimensional($obj,['code','user'=>['id','country'=>['id','name']],"access_token"]);
    
    

    【讨论】:

      【解决方案2】:

      我相信这种方法有效。我颠覆了你的逻辑,我没有搜索 $array 以查看其键是否与 $keys 中的任何一个匹配,而是递归搜索 $keys 以查看 $array 是否有任何匹配值。

      function filter_multidimensional(array $array, array $keys) {
          if (empty($keys) || empty($array)) {
              return [];
          }
      
          $val = [];
          // In the structure of $keys, both key and value are technically "keys". 
          // In the example `['code','user'=>['id']]`, 'code' and 'id' are both array *values*,
          // while 'user' is a key. 
          //
          // So, $objectKey is a search key which contains sub-keys, while $key is just a regular string. 
          foreach ($keys as $objectKey => $key) {
              // If $key is an array, then recursively search, and save the results to the $objectKey string. 
              if (is_array($key)) {
                  $val[$objectKey] = filter_multidimensional($array, $key);
              }
              // If the desired key exists, then save the value. 
              else if (array_key_exists($key, $array)) {
                  $val[$key] = $array[$key];
              }
              // Otherwise, $key is a string, but it does not exist at this level of $array,
              // so search the next-level up in $array, and merge the results into this level of $val. 
              else {
                  $val = array_merge($val, filter_multidimensional(nextLevel($array), [$key]));
              }
          }
      
          return $val;
      }
      
      /**
       * Create an array that contains only the array values from $array.
       * 
       * Eg: If given ['a' => '1', 'b' => ['foo' => '2'], 'c' => ['hello' => 'world']],
       * then return ['foo' => '2', 'hello' => 'world']
       *
       * @param array $array
       * @return array
       */
      function nextLevel(array $array) {
          // Merge all of the array values together into one array
          return array_reduce(
              // Strip the keys
              array_values(
                  // Filter to return only keys where the value is an array
                  array_filter(
                      $array, 
                      function ($value) {
                          return is_array($value);
                      }
                  )
              ),
              'array_merge',
              []
          );
      }
      //-------
      
      $result = filter_multidimensional($obj,['code','user'=>['id','country'=>['name']]]);
      

      【讨论】:

      【解决方案3】:

      您可以使用data_getdata_set 的组合来获得您想要的。

      稍微更改输入,使其更加一致。点符号是最简单的。

      $array = [
          "message" => "User Detail",
          "code" => 200,
          "error" => false,
          "results" => [
              "user" => [
                  "id" => 2,
                  "name" => "ali",
                  "country" => [
                      "id" => 50,
                      "name" => "EGY",
                  ],
              ],
              "access_token" => "=PQLkHJYIXB2uKbCq4sXIjD2GpBU2o",
          ],
      ];
      
      $keys = [
          'code' => 'code',
          'user.id' => 'results.user.id',
          'user.country.name' => 'results.user.country.name',
      ];
      
      $results = [];
      foreach ($keys as $set_position => $get_position) {
          data_set($results, $set_position, data_get($array, $get_position));
      }
      

      【讨论】:

      • 感谢您的回答,这是一个非常好的答案,但是正如我在 update 1 中所说: 我不知道json 中的索引路径,它存在于 json 中(这是肯定的),但我必须遍历数组,直到找到 $key
      • 我认为data_get 可以接受占位符。也许像'*'.$get_position 这样的东西可能有用
      猜你喜欢
      • 2012-12-14
      • 1970-01-01
      • 2014-02-01
      • 2019-11-28
      • 1970-01-01
      • 2016-07-03
      • 1970-01-01
      • 2021-03-05
      • 2014-02-11
      相关资源
      最近更新 更多