Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
4 / 4
CRAP
100.00% covered (success)
100.00%
20 / 20
Combination
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
4 / 4
15
100.00% covered (success)
100.00%
20 / 20
 combinationsAll
100.00% covered (success)
100.00%
1 / 1
3
100.00% covered (success)
100.00%
4 / 4
 combinations
100.00% covered (success)
100.00%
1 / 1
5
100.00% covered (success)
100.00%
9 / 9
 combinationsAllCount
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
1 / 1
 combinationsCount
100.00% covered (success)
100.00%
1 / 1
5
100.00% covered (success)
100.00%
6 / 6
<?php
namespace ia\Math;
use \Generator;
/**
 * Combinations of items ['a','b'] => [ ['a'], ['b'], ['a','b'] ]
 *
 */
class Combination {
    /**
     * All combinations of any size, ['a','b'] => [ ['a'], ['b'], ['a','b'] ]
     *   foreach(Combination:cominationsAll([1,2,3]) as $combinationIndex => $combination)
     *
     * @param array $set
     * @return \Generator each combination as an array [ ['a'], ['b'], ['c'], ['a','b'], ['a','c'], ['b','c'], ['a','b','c'] ]
     */
    public static function combinationsAll($set) {
        for($size=1, $limit = count($set); $size <= $limit; ++$size) {
            foreach(self::combinations($set, $size) as $c) {
                yield $c;
            }
        }
    }
    /**
     * All combinations, no duplicates, of size $size in $set as a Generator.
     *  foreach( combinations(['a','b','c'], 2) as $combinationIndex => $combination) =>  each $c is [a,b],[ a,c] and [b,c]
     *
     * @param array $set
     * @param int $size
     * @return \Generator
     */
    public static function combinations($set = [], $size = 0) {
        if($size === 0) {
            yield [];
        } elseif(count($set) > 0) {
            $prefix = [array_shift($set)];
            foreach(self::combinations($set, $size-1) as $suffix) {
                yield array_merge($prefix, $suffix);
            }
            foreach(self::combinations($set, $size) as $next) {
                yield $next;
            }
        }
    }
    /**
     * Number of all combinations for $setLength elements
     *
     * @param int $setLength
     * @return int
     */
    public static function combinationsAllCount(int $setLength) {
        return $setLength > 0 ? 2 ** $setLength - 1 : 0;
    }
    /**
     * Number of combinations of $setLength items grouped in $itemsNumber. considers a,b equal to b,a
     *
     * @param int $setLength
     * @param int $itemsNumber
     * @return int
     */
    public static function combinationsCount(int $setLength, int $itemsNumber) {
        if($itemsNumber > $setLength || $itemsNumber <= 0 || $setLength <= 0) {
            return 0;
        }
        $number = $setLength;
        for($j = 2, $i = $setLength-1, $limit = $setLength - $itemsNumber + 1; $i >= $limit; --$i, ++$j) {
            $number *= $i/$j;
        }
        return floor($number);
    }
}