Php 如何使函数更快(函数在多维数组中循环)?

Php 如何使函数更快(函数在多维数组中循环)?,php,function,Php,Function,我的功能非常慢!有没有人知道我做错了什么,或者是否有可能加快速度 function explodeTree($array, $delimiter = "_", $baseval = false) { if(!is_array($array)) return false; $splitRE = "/" . preg_quote($delimiter, "/") . "/"; $returnArr = array(); foreach ($array as $key

我的功能非常慢!有没有人知道我做错了什么,或者是否有可能加快速度

function explodeTree($array, $delimiter = "_", $baseval = false) {
    if(!is_array($array)) return false;
    $splitRE = "/" . preg_quote($delimiter, "/") . "/";
    $returnArr = array();
    foreach ($array as $key => $val) {
                $parts = preg_split($splitRE, $val['path'], -1, PREG_SPLIT_NO_EMPTY);
                $leafPart = array_pop($parts);
                $parentArr = &$returnArr;
                foreach ($parts as $part) {
                    if (!isset($parentArr[$part])) {
                        $parentArr[$part] = array();
                    } elseif (!is_array($parentArr[$part])) {
                        if ($baseval) {
                            $parentArr[$part] = array("__base_val" => $parentArr[$part]);
                        } else {
                            $parentArr[$part] = array();
                        }
                    }
                    $parentArr = &$parentArr[$part];
                }
                if (empty($parentArr[$leafPart])) {
                    $parentArr[$leafPart] = $val;
                } elseif ($baseval && is_array($parentArr[$leafPart])) {
                    $parentArr[$leafPart]["__base_val"] = $val;
                }

    }
    return $returnArr;
}
前的数组:

array(4) {
  [0]=>
  array(3) {
    ["path"]=>
    string(30) "Volumes/folder1/horse/fred"
    ["age"]=>
    string(2) "12"
    ["name"]=>
    string(4) "fred"
  }
  [1]=>
  array(3) {
    ["path"]=>
    string(28) "Volumes/folder1/cat/john"
    ["age"]=>
    string(2) "10"
    ["name"]=>
    string(4) "john"
  }
  [2]=>
  array(3) {
    ["path"]=>
    string(27) "Volumes/folder2/cat/sam"
    ["age"]=>
    string(2) "11"
    ["name"]=>
    string(3) "sam"
  }
  [3]=>
  array(3) {
    ["path"]=>
    string(32) "Volumes/folder2/cat/cat/john"
    ["age"]=>
    string(2) "16"
    ["name"]=>
    string(4) "john"
  }
}
使用函数后的数组:

array(1) {
  ["Volumes"]=>
  array(2) {
    ["folder1"]=>
    array(2) {
      ["horse"]=>
      array(1) {
        ["fred"]=>
        array(3) {
          ["path"]=>
          string(30) "Volumes/folder1/horse/fred"
          ["age"]=>
          string(2) "12"
          ["name"]=>
          string(4) "fred"
        }
      }
      ["cat"]=>
      array(1) {
        ["john"]=>
        array(3) {
          ["path"]=>
          string(28) "Volumes/folder1/cat/john"
          ["age"]=>
          string(2) "10"
          ["name"]=>
          string(4) "john"
        }
      }
    }
    ["folder2"]=>
    array(1) {
      ["cat"]=>
      array(2) {
        ["sam"]=>
        array(3) {
          ["path"]=>
          string(27) "Volumes/folder2/cat/sam"
          ["age"]=>
          string(2) "11"
          ["name"]=>
          string(3) "sam"
        }
        ["cat"]=>
        array(1) {
          ["john"]=>
          array(3) {
            ["path"]=>
            string(32) "Volumes/folder2/cat/cat/john"
            ["age"]=>
            string(2) "16"
            ["name"]=>
            string(4) "john"
          }
        }
      }
    }
  }
}

您可能会遇到大量的内存重新分配。如果添加
$begin=microtime(true)foreach
顶部的code>,然后是
printf(“%0.6f',microtime(true)-$begin)在循环结束时,您是否看到时间保持在大致稳定的水平上,还是随着执行的推进而变慢


看起来你在建一个trie。在这种情况下可能有用。

无论
$baseval
TRUE
还是
FALSE
,您的代码似乎都会产生相同的输出。以下代码生成相同的输出,运行速度很快,并且优雅地忽略了
$baseval
的值:

function explodeTree(array $array, $delimiter = "_", $baseval = false)
{
    # Build the output here
    $returnArr = array();

    foreach ($array as $item) {
        # Split the path using the delimiter, drop the empty segments
        $pieces = array_filter(explode($delimiter, $item['path']));
        # Turn the path into a nested array
        # Each component of the path is the only key on its level
        # Build it from the leaf up to the root
        $a = array_reduce(
            array_reverse($pieces),        # Start from the leaf
            function (array $carry, $piece) {     # Create parent node...
                return array($piece => $carry);   # ... use the path piece as key
            },
            $item                          # Put the item itself as leaf
        );

        # Combine the new path (nested arrays) into the existing tree
        # array_merge_recursive() takes care of all the levels
        $returnArr = array_merge_recursive($returnArr, $a);
    }

    # That's all
    return $returnArr;
}
添加$baseval 我认为
$baseval
的目的是,如果后续路径向叶节点添加子节点,则将项的原始属性放入键
\uu base\u val
下的新条目中。例如,如果最后一个条目的
'Volumes/folder2/cat/sam/john'
路径
,则当前代码的输出以以下内容结束:

["folder2"]=>
array(1) {
  ["cat"]=>
  array(1) {
    ["sam"]=>
    array(4) {
      ["path"]=>
      string(23) "Volumes/folder2/cat/sam"
      ["age"]=>
      string(2) "11"
      ["name"]=>
      string(3) "sam"
      ["john"]=>
      array(3) {
        ["path"]=>
        string(28) "Volumes/folder2/cat/sam/john"
        ["age"]=>
        string(2) "16"
        ["name"]=>
        string(4) "john"
      }
    }
  }
}
但预期产出应该是(我认为):

无法修改上述函数以生成此输出
array\u merge\u recursive();它只是将它们结合起来

需要对功能进行彻底的重新思考和重写:

function explodeTree(array $array, $delimiter = "_", $baseval = false)
{
   # Build the output here
   $returnArr = array();

   foreach ($array as $item) {
      # Split the path using the delimiter, drop the empty segments
      $pieces = array_filter(explode($delimiter, $item['path']));
      # Keep a reference to the current node; start from the root of the tree we build
      $pos = &$returnArr;
      foreach ($pieces as $piece) {
        if (! array_key_exists($piece, $pos)) {
            # The path component doesn't exist in the tree; add it
            $pos[$piece] = array();
        } elseif ($baseval && array_key_exists('path', $pos[$piece])) {
            # The component exists, it is a leaf node (has 'path' property) and $baseval is TRUE
            # Save the existing node content
            $val = $pos[$piece];
            # Replace it with a new level; store the old leaf in '__base_val'
            $pos[$piece] = array('__base_val' => $val);
        }
        # Advance to the next level
        $pos = &$pos[$piece];
      }

      # If $baseval is TRUE, make sure we don't mix leaf nodes with inner nodes
      if ($baseval && ! empty($pos)) {
         # The node already has children; put the item in '__base_val'
         $pos['__base_val'] = $item;
      } else {
         # The node was just added; store $item in it
        $pos = array_merge($pos, $item);
      }

      unset($pos);
   }

   return $returnArr;
}

提供示例数据、解释函数的功能以及“极慢”在秒数方面的含义,这些都有助于我们帮助您。每个循环中的正则表达式都会使它变慢。为了使事情快速进行,它必须做少量的工作。这就是我们实现性能的方法。探查器将准确地告诉您CPU在这段代码中花费的时间。研究使用xdebug进行评测和webcachegrind显示结果。如何调用该函数?参数
$delimiter
的默认值为
,但您发布的输入数组中没有
$baseval
的目的是什么?@Mjh:我发布了一个示例数组。但是当我有很多内容时,数组需要几秒钟才能恢复created@axiac我这样称呼它:
$my\u new\u array=explodeTree($array,“/”)非常感谢!我测试了你的功能,但不幸的是加载时间变长了。
function explodeTree(array $array, $delimiter = "_", $baseval = false)
{
   # Build the output here
   $returnArr = array();

   foreach ($array as $item) {
      # Split the path using the delimiter, drop the empty segments
      $pieces = array_filter(explode($delimiter, $item['path']));
      # Keep a reference to the current node; start from the root of the tree we build
      $pos = &$returnArr;
      foreach ($pieces as $piece) {
        if (! array_key_exists($piece, $pos)) {
            # The path component doesn't exist in the tree; add it
            $pos[$piece] = array();
        } elseif ($baseval && array_key_exists('path', $pos[$piece])) {
            # The component exists, it is a leaf node (has 'path' property) and $baseval is TRUE
            # Save the existing node content
            $val = $pos[$piece];
            # Replace it with a new level; store the old leaf in '__base_val'
            $pos[$piece] = array('__base_val' => $val);
        }
        # Advance to the next level
        $pos = &$pos[$piece];
      }

      # If $baseval is TRUE, make sure we don't mix leaf nodes with inner nodes
      if ($baseval && ! empty($pos)) {
         # The node already has children; put the item in '__base_val'
         $pos['__base_val'] = $item;
      } else {
         # The node was just added; store $item in it
        $pos = array_merge($pos, $item);
      }

      unset($pos);
   }

   return $returnArr;
}