在PHP中以及对于某些我们无法使用语言数组搜索功能(我认为)的数组,找到直到找到的典型搜索算法可以通过以下方式实现:
$found = false;
while (list($key, $alreadyRP) = each($this->relatedProducts) && !$found) {
if ($alreadyRP->getProduct()->getId() === $rp->getProduct()->getId()) {
$found = true;
}
}
if (!$found) {
// Do something here
}
请把它当作伪代码,我没有执行它。我喜欢它的地方是,如果找到我们想要的东西,它就会优雅地停止。
现在,由于不赞成使用“每个”功能,我必须编写如下代码:
$found = false;
foreach ($this->relatedProducts as $alreadyRP) {
if ($alreadyRP->getProduct()->getId() === $rp->getProduct()->getId()) {
$found = true;
break;
}
}
if (!$found) {
// Do something here
}
在结构化编程中,将“ break”语句放入“ for”循环中是很难的。是的,它是可选的,但是如果我们避免使用它,那么“ foreach”将遍历所有数组,这不是最有效的方法。
在这种情况下,有什么想法可以恢复“每个”所提供的效率和结构吗?
谢谢。
答案 0 :(得分:3)
each()
方法的优点在旁观者的眼中,但是还有其他一些理由更喜欢foreach,包括来自the RFC that led to the deprecation of each()
each()函数几乎在每种可以想象的方式下都不如前者,包括慢10倍以上。
如果该方法的目的是// Do something here
,而$rp
中没有找到$this->relatedProducts
,那么我认为一种更“美丽”的处理方式是提取搜索结果通过将相关产品转化为单独的方法。
protected function inRelatedProducts($id) {
foreach ($this->relatedProducts as $alreadyRP) {
if ($alreadyRP->getProduct()->getId() === $id) {
return true;
}
}
return false;
}
将相关产品搜索移至另一种方法是有利的,因为
// Do something here
所做的任何事情捆绑在一起。它简化了原始方法,因此可以专注于其主要任务
$id = $rp->getProduct()->getId();
if (!$this->inRelatedProducts($id)) {
// Do something here
}
它简化了搜索代码,因为如果它包含在自己的方法中,则只要找到匹配项就可以return true;
,因此您无需中断或跟踪一个$found
变量。
另一方面,如果这是我的项目,那么我将寻找一种方法,通过填充$this->relatedProducts
来消除对此方法的需要,以便按ID索引(假定ID在此处是唯一的),因此确定可以减少到
$id = $rp->getProduct()->getId();
if (isset($this->relatedProducts[$id])) { ...
答案 1 :(得分:1)
如果您要查找不涉及额外变量的重写,则可以将each
调用替换为对current
和next
的调用:
do {
$found = (current($this->relatedProducts)->getProduct()->getId() === $rp->getProduct()->getId());
} while (empty($found) && false !== next($array));
这是一种机械翻译,它仅依赖于each
(强调我的意思)的定义:
从数组中返回当前键和值对,并提前数组光标
它也遭受与原始each
版本相同的缺陷:它不处理空数组。
也就是说,请不要将each
或其任何同胞用于新代码。 这是由一个在RFC上投票“不”的人造成的!为什么?因为表现糟透了:
1017$ cat trial.php
<?php
$array = range(0, 999);
$begin = -microtime(true);
for ($i = 0; $i < 10000; $i++) {
reset($array);
$target = rand(333, 666);
do {
$found = (current($array) === $target);
} while (empty($found) && false !== next($array));
}
printf("%.5f\n", $begin + microtime(true));
$begin = -microtime(true);
for ($i = 0; $i < 10000; $i++) {
$target = rand(333, 666);
foreach ($array as $current) {
if ($current === $target) break;
}
}
printf("%.5f\n", $begin + microtime(true));
1018$ php -d error_reporting=-1 trial.php
8.87178
0.33585
下一个/当前版本的时间为近9秒,而foreach版本的时间为半秒。只是不要。
答案 2 :(得分:0)
看起来每个基本上都是current()
和next()
的一个版本
http://php.net/manual/en/function.current.php
http://php.net/manual/en/function.next.php
each()
给出当前数组项,并移至下一个索引。
current()
给出当前数组项,但不增加索引。
因此,您可以将each()
替换为current()
,并在foreach内部使用next()
将索引上移
next()
提供下一项,并增加索引。
while (list($key, $alreadyRP) = current($this->relatedProducts) && !$found) {
if ($alreadyRP->getProduct()->getId() === $rp->getProduct()->getId()) {
$found = true;
}
next($this->relatedProducts);
}