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;
}