Php 比较/匹配两个大型阵列的最有效方法?

Php 比较/匹配两个大型阵列的最有效方法?,php,algorithm,compare,Php,Algorithm,Compare,我正在用PHP编写一个过程非常密集的函数,它需要尽可能优化以提高速度,因为在极端情况下,它可能需要60秒才能完成。这就是我的情况: 我正在尝试将一组人员与XML工作列表相匹配。人物数组中有我已经分析过的关键字,用空格分隔。这些作业来自一个大的XML文件 它当前的设置如下: $matches = new array(); foreach($people as $person){ foreach($jobs as $job){ foreach($person['keyword

我正在用PHP编写一个过程非常密集的函数,它需要尽可能优化以提高速度,因为在极端情况下,它可能需要60秒才能完成。这就是我的情况:

我正在尝试将一组人员与XML工作列表相匹配。人物数组中有我已经分析过的关键字,用空格分隔。这些作业来自一个大的XML文件

它当前的设置如下:

$matches = new array();
foreach($people as $person){
    foreach($jobs as $job){
        foreach($person['keywords'] as $keyword){
            $count = substr_count($job->title, $keyword);
            if($count > 0) $matches[$job->title] = $count;
        }
    }
}
我用不同的类别做了几次关键字循环。它做了我需要它做的事情,但感觉非常草率,而且这个过程可能需要非常非常长的时间,这取决于人数/工作


有没有更有效或更快的方法?你可以使用职务中的单词索引来提高查找效率:

$jobsByWords = array();
foreach ($jobs as &$job) {
    preg_match_all('/\w+/', strtolower($jobs->title), $words);
    foreach ($words[0] as $word) {
        if (!isset($jobsByWords[$word])) $jobsByWords[$word] = array();
        $jobsByWords[$word][] = &$job;
    }
}
然后您只需迭代人员并检查关键字是否在索引中:

foreach ($people as $person) {
    foreach ($person['keywords'] as $keyword) {
        $keyword = strtolower($keyword);
        if (isset($jobsByWords[$keyword])) {
            foreach ($jobsByWords[$keyword] as &$job) {
                $matches[$job->title] = true;
            }
        }
    }
}
说实话,你的方法有点草率,但我想这是因为你有一些特殊格式的数据,你必须处理?虽然我不只是草率行事,但在处理我认为并非故意的事情时,我看到了一些丢失的数据

我发现你不仅仅是在检查“是职位中的关键字”,而是在检查“职位中的关键字有多少次”,然后你存储了这个。这意味着对于朋友公司的职位
友好朋友
,“关键字”朋友显示3次,因此
$匹配[“朋友公司的友好朋友”]=3
。但是,由于您在成为每个循环的
$people
之前声明了
$matches
,这意味着您在新人拥有该关键字时会继续写入该值。换句话说,如果第一个人有关键字“friend”,则
$matches[“friendly friend of the friend company”]
设置为3。然后,如果第二个人有关键字“friendly”,则该值被过度写入,
$matches[“friendly friend of the friend company”]
现在等于1

我想你想做的是计算一下有多少人拥有一个包含在职位中的关键字。在这种情况下,您不必计算
$keyword
$job->title
中出现的次数,只需查看是否出现,并做出相应的响应即可

$matches = new array();
foreach($people as $person){
    foreach($jobs as $job){
        foreach($person['keywords'] as $keyword){
            if(strpos($job->title, $keyword) !== FALSE) /* "If $keyword exists in $job->title" */
                $matches[$job->title]++; /* Increment "number of people who match" */
        }
    }
}
另一种可能性是,你想知道一个人有多少关键字与一个职位相匹配。在这种情况下,每个人都需要一个单独的数组。这只需稍加修改即可完成

$matches = new array();
foreach($people as $person){
    $matches[$person] = new array();
    foreach($jobs as $job){
        foreach($person['keywords'] as $keyword){
            if(strpos($job->title, $keyword) !== FALSE) /* "If $keyword exists in $job->title" */
                $matches[$person][$job->title]++; /* Increment "number of keywords which match" */
        }
    }
}
或者,您也可以返回计算关键字现在匹配的次数,因为每个人这实际上是一个有意义的值(“工作匹配得如何”)


本质上,在解决使循环高效的问题之前,您需要弄清楚您的循环真正想要完成的是什么。找出这一点,那么提高效率的最佳选择就是将循环的迭代次数减少到最小,并使用尽可能多的内置函数,因为这些函数是用C(一种非解释性的,因此运行速度更快的语言)实现的。

您考虑过使用关系数据库(例如:MySQL)吗而不是“大XML文件”?因为,你知道,它们是为此而设计的。为什么你要一次匹配一个人的关键词?如果要使用substr_count函数,为什么不传递一个更大的字符串作为第二个参数,即所有关键字的集合?使用xpath搜索XML文件不是更容易吗?@NullUserException,作业来自一个动态的提要,不幸的是,它超出了我们的控制范围@萨加尔五世,我不明白你的意思。但是阻止我改变的是关键字实际上是数组中的索引,它们的值是该关键字出现的次数。我没有在我的例子中说明这一点,但它让我计算出匹配结果的分数。关键字是实际的关键字,还是也可能是关键短语?是的,为了保持简单,我省略了很多细节,并尝试将重点放在整体结构上。不过,你说得太对了。目前,关键字是数组中的索引,而值是它们出现在此人身上的次数。然后,在匹配作业时,它计算关键字在作业中出现的次数,并在不同的“匹配”数组中给它一个“分数”(关键字值*匹配数),最终让我们对相关性进行排序。在这种情况下,需要计算出现的次数(从而单独解析每个字符串)确实给了你一个独特的算法复杂性的情况。我肯定会建议初学者把人和工作的清单尽量少(如果你不输出结果,就不要为人数)。Nick也考虑给每个工作一个包含所有词汇的数组。计算机比较两个数组要快得多/容易得多,因为如果单词确实存在,您确切地知道它的起始位置。基本上,你只检查尽可能多的位置,因为有单词,而不是字母。因此,
$job->wordArray=array('friendly','friend','of','the','friend','company')。在此之后,查看
array\u count\u values()
array\u key\u exists()
以查找匹配数。@Nick注意,新方法将区分“友好”和“朋友”,但这可能很好,因为它将区分“猫”和“餐饮”谢谢,我将试一试。现在,我正在使用关键字周围带有单词边界的正则表达式来区分像“猫”和“餐饮”这样的单词,这可能对我的速度问题没有帮助。不幸的是,每个人都必须进行分析,而且无法避免,因为我需要显示所有人并能够进行排序
$matches = new array();
foreach($people as $person){
    $matches[$person] = new array();
    foreach($jobs as $job){
        foreach($person['keywords'] as $keyword){
            if(strpos($job->title, $keyword) !== FALSE) /* "If $keyword exists in $job->title" */
                $matches[$person][$job->title]++; /* Increment "number of keywords which match" */
        }
    }
}
$matches = new array();
foreach($people as $person){
    $matches[$person] = new array();
    foreach($jobs as $job){
        foreach($person['keywords'] as $keyword){
            if($count = substr_count($job->title, $keyword)) /* if(0) = false */
                $matches[$person][$job->title] += $count; /* Increase "number of keywords which match" by $count */
        }
    }
}