通过键在php中重构多维json

Posted

技术标签:

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

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

    作为输入:

    "message": "User Detail",
    "code": 200,
    "error": false,
    "results": 
        "user": 
            "id": 2,
            "name": "ali",
            "country": 
                "id": 50,
                "name": "EGY"
            
        ,
        "access_token": "=PQLkHJYIXB2uKbCq4sXIjD2GpBU2o"
    

    作为输入:$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,所以我的代码必须适应。这就是我想要做的。

【问题讨论】:

【参考方案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']]]);

【讨论】:

非常感谢,这真的很棒!!! ,只是一个小问题:我相信我们应该在设置值之前检查父键名>>检查一下:pastebin.com/embed_iframe/2iUksnFY 这里是问题的代码响应:pastebin.com/embed_iframe/QuZQLCac?theme=dark 有什么解决办法吗? ,【参考方案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 这样的东西可能有用

以上是关于通过键在php中重构多维json的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET Core从存储过程中获取Json的重构方法

天狮集团参与讨论《全球供应链布局及重构》话题

PHP 杂谈《重构-改善既有代码的设计》之一 重新组织你的函数

重构 JSON 对象数组

使用 Golang 重构 Json

使用 javascript 重构 json 对象