Jack hardcastle
Jack hardcastle

Reputation: 2875

Array Filter limit amount of results PHP

I have the following method

public function getNextAvailableHousesToAttack(\DeadStreet\ValueObject\House\Collection $collection, $hordeSize)
{
    $houses = $collection->getHouses();

    $housesThatCanBeAttacked = array_filter($houses, function($house) use (&$hordeSize) {
        if(!isset($house)) {
            return false;
        }
        $house = $this->houseModel->applyMaxAttackCapacity($house, $hordeSize);
        if($this->houseModel->isAttackable($house)) {
            return $house;
        }
        return false;
    });

    return $housesThatCanBeAttacked;

However, this array can be huge.

I want to limit $housesThatCanBeAttacked to whatever the size of $hordeSize is set to, as I only need as many houses as there are zombies in the horde to attack this round.

However, this array $housesThatCanBeAttacked could end up containing 1 million houses, where there are only 100 in the zombie horde.

Is there a way to limit the size of this array built from the callback?

Upvotes: 0

Views: 1296

Answers (2)

BadHorsie
BadHorsie

Reputation: 14544

You could simply use a loop, and stop processing the array when you have enough houses.

$houses = $collection->getHouses();
housesThatCanBeAttacked[];
$i = 0;

foreach ($houses as $house) {
    $house = $this->houseModel->applyMaxAttackCapacity($house, $hordeSize);
    if ($this->houseModel->isAttackable($house)) {
        housesThatCanBeAttacked[] = $house;
        if (++$i == $hordeSize) {
            break;
        }
    }
}

Upvotes: 1

Dima Zbarski
Dima Zbarski

Reputation: 275

I would add a counter of houses outside of callback and use it inside callback to skip all excessive houses. Here is how a solution can look like:

public function getNextAvailableHousesToAttack(\DeadStreet\ValueObject\House\Collection $collection, $hordeSize)
{
    $houses = $collection->getHouses();
    $counter = $hordeSize;

    $housesThatCanBeAttacked = array_filter($houses, function($house) use (&$hordeSize, &$counter) {
        if($counter == 0 && !isset($house)) {
            return false;
        }
        $house = $this->houseModel->applyMaxAttackCapacity($house, $hordeSize);
        if($this->houseModel->isAttackable($house)) {
            $counter--;
            return $house;
        }
        return false;
    });

    return $housesThatCanBeAttacked;

This way you array_filter won't return more then $counter values.

Upvotes: 0

Related Questions