【问题标题】:How can I recursively check an array of file include dependencies for other dependencies?如何递归检查文件包含依赖项的数组以获取其他依赖项?
【发布时间】:2010-08-10 21:34:13
【问题描述】:

为了解释我的问题,让我首先指向这个数组:

<?php
$_depends = array(
    '/Scripting/jquery.hyponiqs/jquery.dropdown.js' => array(
        "/Scripting/jquery.externals/jquery.resize.js",
        "/Scripting/jquery.externals/jquery.topzindex.js",
        "/Scripting/jquery.externals/jquery.timers.js",
        "/Scripting/jquery-ui.min.js",
        "/Scripting/jquery.hyponiqs/hyponiqs.core.js",
    ),
    '/Script/UI/Dialogs.js' => array(
        "/Scripting/jquery.externals/jquery.resize.js",
        "/Scripting/jquery.externals/jquery.topzindex.js"
    ),
    '/Script/Display/List.js' => array(
        "/Scripting/jquery.externals/jquery.timers.js"
    )
);
?>

只要包含一个 JavaScript 文件,就会根据这个数组检查它的依赖关系。然后将每个文件的所有依赖项添加到最终的$includes 数组中。当我添加一个包含依赖项并且其中一个依赖项也有自己的依赖项时,问题就出现了,例如:

<?php
$_depends = array(
    '/Scripting/jquery.hyponiqs/jquery.dropdown.js' => array(
        "/Scripting/jquery.externals/jquery.resize.js",
        "/Scripting/jquery.externals/jquery.topzindex.js",
        "/Scripting/jquery.externals/jquery.timers.js",
        "/Scripting/jquery-ui.min.js",
        "/Scripting/jquery.hyponiqs/hyponiqs.core.js",
    ),
    '/Script/UI/Dialogs.js' => array(
        "/Scripting/jquery.externals/jquery.resize.js",
        "/Scripting/jquery.externals/jquery.topzindex.js"
    ),
    '/Script/Display/List.js' => array(
        "/Scripting/jquery.externals/jquery.timers.js"
    ),
    '/Script/UI/Calendar/Main.js' => array(
        "/Scripting/jquery-ui.min.js",
        "/Script/UI/Dialogs.js"
    )
);
?>

如您所见,添加的'/Script/UI/Calendar/Main.js' 依赖于"/Script/UI/Dialogs.js",而"/Script/UI/Dialogs.js" 有自己的依赖关系。

我知道我必须递归检查依赖数组和最终包含数组,但我似乎无法理解逻辑。这里有一点帮助可能会很好。

更新

我将所有内容都封装在一个类中以说明其用途(尽管实际的类要复杂得多,并且具有各种其他包含处理功能:

<?php
class Script_Depends {
    private $_includes = array();

    private $_depends = array(
        '/Scripting/jquery.hyponiqs/jquery.dropdown.js' => array(
            "/Scripting/jquery.externals/jquery.resize.js",
            "/Scripting/jquery.externals/jquery.topzindex.js",
            "/Scripting/jquery.externals/jquery.timers.js",
            "/Scripting/jquery-ui.min.js",
            "/Scripting/jquery.hyponiqs/hyponiqs.core.js",
        ),
        '/Script/UI/Dialogs.js' => array(
            "/Scripting/jquery.externals/jquery.resize.js",
            "/Scripting/jquery.externals/jquery.topzindex.js"
        ),
        '/Script/Display/List.js' => array(
            "/Scripting/jquery.externals/jquery.timers.js"
        ),
        '/Script/UI/Calendar/Main.js' => array(
            "/Script/UI/Dialogs.js",
            "/Scripting/jquery-ui.min.js"
        )
    );

    public function includes($includes)
    {
        if (is_string($includes)) $includes = array($includes);

        foreach ($includes as $include) {
            if (isset($this->_depends[$include])) {
                $this->_includes = $this->includes($this->_depends[$include]);
                array_push($this->_includes, $include);
            }
            else {
                array_push($this->_includes, $include);
            }
        }

        $this->_includes = array_unique($this->_includes);

        return $this->_includes;
    }
}
?>

【问题讨论】:

    标签: php recursion include dependencies


    【解决方案1】:
    • 保留一个堆栈,最初是您的初始依赖项 (stack)
    • 保留一个包含所有(传递)依赖项的空数组 (deps)
    • 虽然堆栈不是empty
      • pop 最后一个元素 (el)
      • el 添加到deps
      • 循环遍历el的依赖
        • 如果依赖是indeps,什么都不做
        • 否则,push 将其转为stack

    【讨论】:

    • 感谢您的帮助。我不敢相信答案就这么简单......而且我没有看到它!
    【解决方案2】:

    您要查找的函数称为 flatten。它采用递归列表并返回每个级别的所有元素。

    这里的cmets中有一些php中的实现:http://php.net/manual/en/function.array-values.php

    这里是 javascript 中的一个实现:http://tech.karbassi.com/2009/12/17/pure-javascript-flatten-array/

    【讨论】:

    • 不,这不是压扁。展平是当您拥有一个多维数组并将一个或多个级别折叠到基础级别时。
    • 也许我应该进一步解释一下:并非所有这些都将始终包含在内,有时仅会包含其中的一部分,具体取决于需要什么。 IE。我可能在一个应用程序中只包含“/Script/Display/List.js”,但在另一个应用程序中包含“/Script/UI/Calendar/Main.js”和“/Scripting/jquery.hyponiqs/jquery.dropdown.js”。
    • 你是对的;我读得太快了。这是图中的边列表;根本问题是从一组起始节点中找到图中的可达节点。
    【解决方案3】:

    试试这个:

    function getDependentFiles($file, $dependencies) {
        $fileIndex = array();
        $queue = array($file);
        while (count($queue)) {
            $f = array_shift($queue);
            if (!isset($fileIndex[$f])) {
                if (array_key_exists($f, $dependencies) && is_array($dependencies[$f])) {
                    $queue = array_merge($queue, $dependencies[$f]);
                }
                $fileIndex[$f] = true;
            }
        }
        return array_keys($fileIndex);
    }
    var_dump(getDependentFiles('/Script/UI/Calendar/Main.js', $_depends));
    

    这基本上实现了Artefacto描述的算法。

    【讨论】:

    • 谢谢......但我已经在我得到这个答案时实现了答案。而且,感谢你们俩的帮助!
    【解决方案4】:

    看看这是否能解决问题——你的功能的一个小模块。

    (顺便说一句,由于您的命名约定,这令人费解:$includes、$include、$this->_includes 和 $this->includes()!建议您使用更好的名称。我已将该函数重命名为calculate_includes,但你也应该清理其他的。)

    public function calculate_includes($includes) {
    
            foreach ((array)$includes as $include) {
    
                if(in_array($include, $this->_includes)) continue;
    
                if (isset($this->_depends[$include])) {
                    $this->_includes = $this->calculate_includes($this->_depends[$include]);
                } else {
                    array_push($this->_includes, $include);
                }
            }
    
            $this->_includes = array_unique($this->_includes);
    
            return $this->_includes;
        }
    

    【讨论】:

    • 虽然这对我的实现来说是一个有趣且有用的 mod,但 array_unique() 调用会自动处理并消除双推元素。
    • 加一行不是为了防止被骗——是为了防止无限递归。
    猜你喜欢
    • 2013-04-17
    • 2016-07-19
    • 1970-01-01
    • 2014-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多