我有一段代码在运行模拟。
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
包含一个最多超过100万个结果的数组($getHouses
(,尽管它永远不需要对所有这些结果进行迭代,但由于数组的巨大规模,行$houses = array_values(array_filter($houses))
花费了很长时间(每次运行该行最多3秒(。
我必须保持数组索引为数字,并且这个数组中不能有空值。
我希望unset($array[$i])
会在元素在键中被取消"向下"设置后移动数组元素,所以如果我是unset($array[5])
,那么$array[6]
就会变成$array[5]
,但它似乎不是这样工作的。
break
条件之所以存在,是因为在迭代中,如果迭代中的房屋没有受到攻击,那么可以安全地假设阵列中的任何其他房屋也没有受到攻击。
有没有一种最佳的、资源较少的方式来实现这一点?
我现在不能真的重组它,因为它正在单元测试中,我需要它尽快完成,这种方法不太好,但嗯。
我认为实现这一点最无痛的方法是这样的:
当你在房子的数组中循环时,你需要在数组中取消设置一些东西,你可以欺骗循环本身。
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循环开始之前为break条件设置一个变量。
$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.
}
我们只会删除数组中的最后一个元素,因此它将保持为数字。