我有一段运行模拟的代码。
public function cleanUpHouses(\DeadStreet\ValueObject\House\Collection $collection)
{
$houses = $collection->getHouses();
$housesLength = count($houses);
$filterValues = false;
for($i = 0; $i < $housesLength; $i++) {
if(!$this->houseModel->hasBeenAttacked($houses[$i])) {
break;
}
$houses[$i]->setCurrentAttackers(0);
if($this->houseModel->requiresDestroying($houses[$i])) {
$houses[$i] = null;
$filterValues = true;
}
}
if($filterValues) {
$houses = array_values(array_filter($houses));
}
$collection->setHouses($houses);
return $collection;
}
但是,$collection
包含一个数组($getHouses
),最多可达100万条结果,但它永远不需要迭代所有这些结果,行$houses = array_values(array_filter($houses))
是由于数组的大小,所以需要很长时间(每次运行此行时最多3秒)。
我必须保持数组索引为数字,并且此数组中不能有空值。
我希望unset($array[$i])
在键中取消设置元素之后移位数组元素,所以如果我去unset($array[5])
,那么$array[6]
将成为$array[5]
但是它看起来不像这样。
break
有条件的是因为,如果迭代中的房子没有被攻击,那么在迭代中可以安全地假设阵列中的任何其他房屋也没有被攻击。
是否有最佳的,资源较少的方法来实现这一目标?
我现在不能真的重组这个,因为它是在单元测试中我需要尽快完成,方法不是很好,但是呃。
答案 0 :(得分:0)
我认为实现这一目标最无痛苦的方法是这样的:
当你循环遍历房屋阵列时,你需要在数组中取消设置,你可以欺骗循环本身。
if($this->houseModel->requiresDestroying($houses[$i])) {
// $houses[$i] = null;
// when you unset the $i house in the array,
// you can simply switch it with the last one in the array, keeping in mind,
// that this may break your logic with the break condition, so will want to change that as well.
$lastHouse = $houses[$housesLength - 1];
$houses[$i] = $lastHouse;
unset($houses[$housesLength - 1]);
$i--;
$housesLength--; // by doing the top two lines we would make the loop check the last house again.
$shouldBreak = false; // this will keep your logic with the break if later.
// $filterValues = true; // you can remove this line here.
}
您可能希望在for循环开始之前为中断条件设置变量。
$shouldBreak = true;
for($i = 0; $i < $housesLength; $i++) {
...
现在为条件本身
if(!$this->houseModel->hasBeenAttacked($houses[$i]) && true === $shouldBreak) {
break;
} else {
$shouldBreak = true; // we set $shouldBreak = false when we unset the last house,
// so we would want to keep checking the houses not to break the logic.
}
我们只删除数组中的最后一个元素,因此它将保持数字。