当前位置: 首页 > 知识库问答 >
问题:

检查数组的递归

荀辰钊
2023-03-14

在PHP中,检查数组是否为递归数组的最佳方法是什么?

给定以下代码:

<?php 
$myarray = array('test',123); 
$myarray[] = &$myarray; 
print_r($myarray); 
?> 

从PHP手册:

print\u r()在到达数组的第三个元素时将显示递归

似乎没有其他方法可以扫描数组中的递归引用,因此如果需要检查它们,则必须使用print\u r()及其第二个参数来捕获输出并查找单词RECURSION。

还有更优雅的检查方式吗?

附:这就是我如何使用regex和print\u r()检查和获取递归数组键的方法

$pattern = '/\n            \[(\w+)\] => Array\s+\*RECURSION\*/';
preg_match_all($pattern, print_r($value, TRUE), $matches);
$recursiveKeys =  array_unique($matches[1]);

谢谢

共有3个答案

韩景胜
2023-03-14

前段时间我已经深入研究过这个问题,但我找不到任何有用的机制来检测PHP数组中的递归。

问题归根结底是,是否有可能判断两个PHP变量是否引用同一事物。

如果您使用的是对象而不是数组(甚至是数组中的对象),那么这是可能的,因为您可以使用spl\u object\u hash()查找两个对象是否是相同的引用。因此,如果结构中有对象,那么可以通过遍历树并比较对象来检测递归。

然而,对于常规变量(即非对象),使用标准PHP无法轻松检测到这一点。

解决方法是使用print\u r()(如您所知)或var\u dump(),但这两种解决方案都不是特别优雅的解决方案。

xDebug还提供了一个函数,可以提供帮助,xDebug\u debug\u zval(),但这显然只有在安装了xDebug的情况下才可用,这在生产系统上是不推荐的。

此处提供更多建议和建议。

傅翰池
2023-03-14

以下函数比公认答案中的代码更简单[意见],似乎适用于我能够设计的任何用例。虽然我还没有做过广泛的基准测试,但它似乎速度惊人,通常需要几微秒。如果有问题,如果有人能指出,我将不胜感激?

// returns TRUE iff the passed object or array contains
// a self-referencing object or array
function is_r($obj, &$visited=array())
  {
  $visited[] = $obj;
  foreach ($obj as $el)
    {
    if (is_object($el) || is_array($el))
      {
      if (in_array($el, $visited, TRUE))
        return TRUE;
      if (is_r($el, $visited))
        return TRUE;
      }
    }
  return FALSE;
  }
嵇光临
2023-03-14

尝试解决“不可能”的问题总是很有趣的!

下面是一个函数,如果递归发生在顶层,它将检测递归数组:

function is_recursive(array &$array) {
    static $uniqueObject;
    if (!$uniqueObject) {
        $uniqueObject = new stdClass;
    }

    foreach ($array as &$item) {
        if (!is_array($item)) {
            continue;
        }

        $item[] = $uniqueObject;
        $isRecursive = end($array) === $uniqueObject;
        array_pop($item);
        if ($isRecursive) {
            return true;
        }
    }

    return false;
}

在行动中看到它。

在任何级别检测递归显然都会更加棘手,但我认为我们可以同意这似乎是可行的。

下面是递归(双关语并非有意,但令人愉快)解决方案,它可以在任何级别检测递归:

function is_recursive(array &$array, array &$alreadySeen = array()) {
    static $uniqueObject;
    if (!$uniqueObject) {
        $uniqueObject = new stdClass;
    }

    $alreadySeen[] = &$array;

    foreach ($array as &$item) {
        if (!is_array($item)) {
            continue;
        }

        $item[] = $uniqueObject;
        $recursionDetected = false;
        foreach ($alreadySeen as $candidate) {
            if (end($candidate) === $uniqueObject) {
                $recursionDetected = true;
                break;
            }
        }

        array_pop($item);

        if ($recursionDetected || is_recursive($item, $alreadySeen)) {
            return true;
        }
    }

    return false;
}

在行动中看到它。

当然,这也可以通过手动保存堆栈来编写迭代,而不是递归,这将有助于解决非常大的递归级别的问题。

 类似资料:
  • @PeterLawrey我稍微调整了代码如下,因为我只需要洗牌,这是一个享受,我会弹出卡片的堆栈来处理 感谢彼得和所有其他贡献者。M.

  • 问题内容: 我需要检查数组以查看用户输入是否已经存在,并显示一条有关是否存在的消息。第一部分工作正常,但是我尝试创建一种用于单词检查的方法,我不确定自己是否走对了,干杯。 问题答案: 对。您显然已经经历了一个糟糕的思考过程,所以让我们清理一下状况,重新思考一下。 第一步:您需要一些用户输入 第二步:将其与所有先前的用户输入进行比较,以查看是否存在。 如果存在,则返回一条消息,指示已输入值。 否则忽

  • 我想做的每件事都成功了,现在是最后一部分,我需要检查某个id的学生是否有某种疫苗,结果应该是真的或假的。我知道我必须使用ListofFos。contains():'但我不知道如何使用它,也不知道在哪里使用它。

  • 我一直在做一个即时聊天程序,并希望使用户可以“耳语”或私人消息彼此。我实现的方式是用户输入: /W[用户名][消息] 然后将其发送给服务器,服务器将其发送给所有用户。然后用户必须检查它是否发送给他们,这就是方法: 每次在测试时发送a/W时,它总是给出ArrayIndexOutOfBoundsException。我也在发送中修改消息。方法如下: 我还为用户的实际代码添加了一大堆更多的选项,我创建了/

  • 我得到了岩石的价格和数组中每一块岩石的值。我必须递归地(仅使用列出的4个变量)检查所有可能的岩石组合,以找到低于或等于岩石组合允许的最大重量的最高价格。 例如: 在这种情况下,可以找到的最高价格是50,因为20的重量低于25,值是50。这比5-10的权重高,5-10的权重也低于25,但它们的值加起来只有40,小于50。 示例2: 在这种情况下,最高价格是80美元。这是因为权重20 10加起来等于最

  • 问题内容: AngularJs中的内联方法是否可以检查某物是否为数组? 我本以为这样可以工作: 我已经证实它实际上是一个数组。有什么我想念的东西吗? 问题答案: 您可以戴上瞄准镜… 小提琴