ronisaha
12/30/2016 - 6:32 AM

CombinationGenerator example

CombinationGenerator example

<?php

class CombinationGenerator implements \Iterator
{
    private $array;
    private $length;
    private $itemCount;
    private $pos = -1;
    private $binArray = array();
    private $cache = array();

    function __construct(array $array, $length = 0) {
        $this->array = $array;
        $this->itemCount = count($array);
        $this->length = $length;

        if($length > $this->itemCount) {
            throw new \Exception("Cannot pick $length item from $this->itemCount");
        }

        $this->init();

    }
    private function init() {
        $this->buildBinaryArray();
        $this->rewind();
    }

    private function buildBinaryArray() {

        $binaryString = str_repeat(1, $this->itemCount);
        $max = bindec($binaryString);

        for ($i = $max; $i > 0; $i--)
        {
            if (substr_count(decbin($i), "1") == $this->length)
            {
                $this->binArray[] = str_split(str_pad(decbin($i), $this->itemCount, "0", STR_PAD_LEFT));
            }
        }
    }

    function key() {
        return $this->pos;
    }

    function current()
    {
        if (!isset($this->binArray[$this->pos])) {
            return null;
        }

        if(!isset($this->cache[$this->pos])){
            $this->createCache();
        }

        return $this->cache[$this->pos];

    }

    function next() {
        $this->pos++;
    }

    function rewind() {
        $this->pos = 0;
    }

    function valid() {
        return isset($this->binArray[$this->pos]);
    }

    private function createCache()
    {
        $this->cache[$this->pos] = array();

        foreach ($this->binArray[$this->pos] as $indx => $digit) {
            if ($digit == '1') {
                $this->cache[$this->pos][] = $this->array[$indx];
            }
        }
    }

}

class MaxSumFilterIterator extends \FilterIterator
{
    private $maxSum = 0;

    public function __construct(Iterator $iterator , $maxSum )
    {
        parent::__construct($iterator);
        $this->maxSum = $maxSum;
    }

    public function accept()
    {
        $array = $this->getInnerIterator()->current();

        return (array_sum($array)) <= $this->maxSum;
    }
}

//Usages
$array = ['1', '2', '3', '4', '5', '6', '7'];

$allCombinations = new CombinationGenerator($array, 5);

foreach($allCombinations as $key => $subSet){
    echo ' ----- ' . $key . PHP_EOL;
    print_r($subSet);
}

$combinationWithMaxSum = new MaxSumFilterIterator($allCombinations, 16);

foreach($combinationWithMaxSum as $key => $subSet){
    echo ' ----- ' . $key . PHP_EOL;
    print_r($subSet);
}