Php 如何快速查找排序数组中的元素
我是新来这里的,但已经检查了以前关于这方面的帖子,虽然类似,但对于我正在尝试做的事情来说还不够。我有一个包含40K+记录的CSV文件,并检索70K+记录的LDAP记录;两者都存储在多维数组变量中。目标是显示所有不匹配的记录。我目前的解决方案是花20多分钟来处理,效率很低。我创建了一个外部循环,它为每个记录检查LDAP记录集内部循环中的匹配项,如果找到,则跳到下一个记录,并取消LDAP数组索引以缩小下一个循环的数组。我还将两个数组按升序排序,以加快进程。想法、调整、帮助加快流程Php 如何快速查找排序数组中的元素,php,arrays,csv,multidimensional-array,ldap,Php,Arrays,Csv,Multidimensional Array,Ldap,我是新来这里的,但已经检查了以前关于这方面的帖子,虽然类似,但对于我正在尝试做的事情来说还不够。我有一个包含40K+记录的CSV文件,并检索70K+记录的LDAP记录;两者都存储在多维数组变量中。目标是显示所有不匹配的记录。我目前的解决方案是花20多分钟来处理,效率很低。我创建了一个外部循环,它为每个记录检查LDAP记录集内部循环中的匹配项,如果找到,则跳到下一个记录,并取消LDAP数组索引以缩小下一个循环的数组。我还将两个数组按升序排序,以加快进程。想法、调整、帮助加快流程 foreach($
foreach($csvArray as $csvindex=>$csvalue) {
echo "<br />csvArray record: <strong> ".$counter."</strong><br />\n";
if($counter <= 1) {
for ($i = 0, $max=$rs["count"]-1; $i < $max ;$i++) { //loop through ldap array
if($csvalue[0] == $rs[$i]['uid'][0]) { // csv netid & ldap netid
echo "CSV netid: ".$csvalue[0];
echo "<br />matched LDAP array [$i] netid: ".$rs[$i]["uid"][0];
echo "<br />\n";
$matched = $i; //$i represents integer offset in array (ie. $rs[21])
break;
}
}
} else {
unset($rs[$matched]); //remove matched items
$newRS = array_values($rs); //re-indexes array
echo "Size of new LDAP array: ".count($newRS);
for ($i=0, $max=count($newRS); $i<$max; $i++) {
if($csvalue[0] == $newRS[$i]['uid'][0]) { // csv netid & ldap netid
echo "<br />CSV netid: ".$csvalue[0];
echo "<br />matched LDAP array [$i] netid: ".$newRS[$i]["uid"][0];
echo "<br />\n";
$matched = $i; //$i represents integer offset in array (ie. $rs[21])
break;
}
}
}
$counter++;
}
这里有一些代码来替换您的内部循环。它使用二进制搜索。必须在此点之前对LDAP数组进行排序
$workingArray=$newRS;
while($LDAPcount=count($workingArray)) {
$indexToCheck=ceil($LDAPcount/2);
if($csvalue[0] == $workingArray[$indexToCheck]['uid'][0]) { // csv netid & ldap netid
echo "<br />CSV netid: ".$csvalue[0];
echo "<br />matched LDAP array ".$workingArray[$indexToCheck]["uid"][0];
echo "<br />\n";
$matched = $indexToCheck; //$indexToCheck represents integer offset in array (ie. $rs[21])
break;
} else {
if($csvalue[0] < $workingArray[$indexToCheck]['uid'][0]) {
$workingArray=array_slice($workingArray,0,$indextoCheck);
} else {
$workingArray=array_slice($workingArray,$indextoCheck+1);
}
}
}
代替LDAP记录的直数组,可以考虑树二进制或其他方式。您遇到的效率低下是由于每次都从LDAP列表的开头开始。使用二叉树,您可以按照log2n的顺序设置要检查的LDAP记录的最大数量。如果您在运行过程中从LDAP树中删除节点,这也会对一些人有所帮助。我认为您也不会受到太大的性能影响,因为您目前正在经历对LDAP记录进行排序的过程。只需将该排序替换为加载树。对于70k条记录,LDAP树中最多可检查17条记录。感谢您的回复。我不熟悉LDAP树。如果你能给我指一个参考或例子,那将是一个很大的帮助。我还希望尽可能减少ldap调用的数量。谢谢使用当前已排序的LDAP记录列表,还可以进行二进制搜索。将第一个记录与中间记录进行比较。如果小于中间记录,则下一个LDAP工作列表是LDAP数组的前半部分。然后,再次与中间记录进行比较。重复此操作,直到找到或工作数组长度=0。这种方法实际上比使用树更简单。它正在做你现在正在做的事情,但不是每次都从一开始就开始。太好了,谢谢你!我不是计算机科学专业的学生,所以我首先要考虑算法。看起来会很好用的。稍后我将对此进行一次尝试并发表评论。请注意,此参考说明array_slice效率低下。array_slice本身并不低效,但wikibooks参考是正确的,因为用于此目的的slice效率低下。他们给出了一个更好的算法,使用两个变量来跟踪所需数组部分的顶部和底部。他们的版本很好。
$workingArray=$newRS;
while($LDAPcount=count($workingArray)) {
$indexToCheck=ceil($LDAPcount/2);
if($csvalue[0] == $workingArray[$indexToCheck]['uid'][0]) { // csv netid & ldap netid
echo "<br />CSV netid: ".$csvalue[0];
echo "<br />matched LDAP array ".$workingArray[$indexToCheck]["uid"][0];
echo "<br />\n";
$matched = $indexToCheck; //$indexToCheck represents integer offset in array (ie. $rs[21])
break;
} else {
if($csvalue[0] < $workingArray[$indexToCheck]['uid'][0]) {
$workingArray=array_slice($workingArray,0,$indextoCheck);
} else {
$workingArray=array_slice($workingArray,$indextoCheck+1);
}
}
}