【问题标题】:PHP array resolve dot-notated keys to multi-dimensional arrayPHP数组将点表示的键解析为多维数组
【发布时间】:2023-03-14 07:23:01
【问题描述】:

我正在为一些数组的东西而苦苦挣扎。我有一个函数arr_set(),我可以在其中传递一个数组、一个键和一个值(例如,在键“sub.key”上设置一个值“value”,这将创建$array["sub"]["key"],其值为“value”。 我也可以直接设置一个数组($key 将是值,而$value 为空)并分配它 - 也可以,但其中有一个小错误,因为它不会拆分点标记的键放在某个子数组中。

检查代码:

/**
 * Function to set the data
 *
 * @param      $array
 * @param      $key
 * @param null $value
 */
function arr_set(&$array, $key, $value = null) {
    if ($key === null) {
        $array[] = $value;

        return;
    }

    if (is_array($key)) {
        foreach ($key as $k => $v) {
            arr_set($array, $k, $v);
        }

        return;
    }

    $temp = &$array;
    $key = (string)$key;
    $keys = explode(".", $key);
    foreach ($keys as $k) {
        if ((is_array($temp) && !array_key_exists($k, $temp)) || !is_array($temp[$k])) {
            $temp[$k] = [];
        }
        $temp = &$temp[$k];
    }

    $temp = $value;
}

$temp = [
    "live" => [
        "db.name" => "livedb",
        "db"       => [
            "host" => "localhost",
        ],
    ],
];

# Original array
$myArray = [];

# Set the $temp to the $myArray
arr_set($myArray, $temp);

echo "<pre>" . print_r($myArray, true) . "</pre>";

结果是

Array
(
    [live] => Array
        (
            [db.name] => livedb
            [db] => Array
                (
                    [host] => localhost
                )

        )

)    

几乎,但不是很完美——你看到“db.name”键了吗?这实际上不应该存在,而是键“db”应该具有与“host”相同级别的子键“name”。希望我提供了足够的信息以使问题易于理解。 思考如何解决这个小错误以某种方式使我的大脑崩溃,我得出的结论是,如果有解决方案,它将导致超级混乱,蹩脚,骇人听闻的无性能代码。希望不会,但我放弃了这一点^^

我用谷歌搜索并搜索了很多,但找不到任何可行的解决方案。这个库https://github.com/adbario/php-dot-notation 做不到,laravel 的array_set() 也做不到。有什么想法吗?

(PS: sry for bad English, German here)

【问题讨论】:

  • 看来$myArray = [ "key" =&gt; "value", ]; 可以完全从您的问题中删除(只需在您的过程中稍后将其与递归结果合并。
  • @mickmackusa 当然,但这不是我的问题的重点。
  • 没错,我们需要隔离您的需求,并从您的问题中删除多余的部分。
  • 我认为你的问题不值得投票,所以我现在就投票。也就是说,请不要认为此页面“已完成”。每个页面都应该得到系统认可的分辨率。如果您已经解决了自己的问题,请将其作为答案发布,并附上解释,旨在让未来的研究人员了解它的工作原理、可能无法解决的任何边缘案例以及为什么它是一个好的解决方案。用SOLVED 标记你的标题并不是这里的事情。请从您的问题中清除任何不必要的文本——内容最少时最好。
  • 请发布您的答案,当足够的时间过去后,您将能够用绿色勾号标记它。如果其他人出现并提供了更好的解决方案,您可以根据需要移动绿色对勾(标记其他志愿者的答案将获得 5 个代表点数)。

标签: php arrays recursion


【解决方案1】:

我创建了一个简单的解决方案,它没有考虑一些边缘情况或错误处理,但如果您想要一个递归解决方案,您可以从这个方向开始。我们也可以使用您的字符串参数创建一个递归函数,但它很难使用,所以我为此创建了第二个函数,它使用了爆炸数组。我们立即使用它,我们爆炸了密钥字符串。

function arr_set(array &$array, $key, $value)
{
    $keys = explode(".", $key);
    arr_set_recursive($array, $keys, $value);
}

在递归中,我们传递给我们使用的数组、剩下的键和要插入的值。我们必须提供递归退出以防止错误或堆栈溢出,因此我们检查是否还有任何键。在每一步,我们从键数组中移出一个键。所以首先我们有“db”,然后是“name”。我们检查这里是否还有更多的钥匙。如果我们不这样做,那么我们将值设置为先前移动的键。否则我们会更深一步,整个事情都会重复。

function arr_set_recursive(array &$array, array $keys, $value)
{
    if (count($keys) > 0) {
        $key = array_shift($keys);
        if (count($keys) == 0) {
            $array[$key] = $value;
        } else {
            if (!array_key_exists($key, $array)) {
                $array[$key] = [];
            }
            arr_set_recursive($array[$key], $keys, $value);
        }
    }
}

您可以在这里查看解决方案:http://sandbox.onlinephpfunctions.com/code/758bd7ed7c3cfc5bc33b4f06317be97b83958771

【讨论】:

  • 如果您知道一些会导致问题的特定边缘案例,请分享。
  • 谢谢你,但我已经设法解决了(你的解决方案不符合我的意思)。
  • @cola SO 是一个知识库。不仅仅是一个社区,您可以在其中获得答案并且不要与我们分享。您可以添加自己的经验作为答案吗?所以,您可以将其标记为最佳答案
  • @KoenHollander +1,我了解 SO 的概念,当然我会发布我的解决方案,但不是现在,因为首先我想广泛测试我的代码并检查所有可能性。
  • @cola 太棒了! SO的很多新成员,不明白这个概念。这就是为什么我总是帮助别人,所以每个人都可以从问题中学习
猜你喜欢
  • 2019-06-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多