Created
March 30, 2015 11:24
-
-
Save martinezdelariva/621553a2b8bef8cd6f2b to your computer and use it in GitHub Desktop.
Cartesian Product Iterator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Usage: | |
$cartesianProductIt = new CartesianProduct(array( | |
new \ArrayIterator(array(1, 2)), | |
new \ArrayIterator(array('a', 'b')) | |
)); | |
// Output on traverse | |
// array(1, 'a'), | |
// array(1, 'b'), | |
// array(2, 'a'), | |
// array(2, 'b'), | |
/** | |
* Class CartesianProductIterator | |
* | |
* When traversing return arrays of items of the Cartesian Product for the set of iterators given. | |
* | |
* Input : array of Iterators. | |
* Output : array of items of Cartesian Product. | |
*/ | |
class CartesianProductIterator implements \Iterator | |
{ | |
/** | |
* @var \int | |
*/ | |
protected $key; | |
/** | |
* @var \Iterator[] | |
*/ | |
protected $iterators = array(); | |
/** | |
* @param \Iterator[] $iterators | |
*/ | |
public function __construct(array $iterators) | |
{ | |
$this->iterators = $iterators; | |
$this->key = 0; | |
} | |
/** | |
* @inheritdoc | |
*/ | |
public function current() | |
{ | |
$cartesianItem = array(); | |
foreach ($this->iterators as $iterator) { | |
$cartesianItem[] = $iterator->current(); | |
} | |
return $cartesianItem; | |
} | |
/** | |
* @inheritdoc | |
*/ | |
public function next() | |
{ | |
/** @var $reverseIterators \Iterator[] */ | |
$reverseIterators = array_reverse($this->iterators); | |
foreach ($reverseIterators as $key => $iterator) { | |
$iterator->next(); | |
if ($iterator->valid()) { | |
$this->rewindIteratorsFromPosition(count($this->iterators) - $key); | |
break; | |
} | |
} | |
$this->key++; | |
} | |
/** | |
* Rewind the latest iterators from $position given | |
* | |
* @param int $position | |
*/ | |
protected function rewindIteratorsFromPosition($position) | |
{ | |
foreach ($this->iterators as $key => $iterator) { | |
if ($key >= $position) { | |
$iterator->rewind(); | |
} | |
} | |
} | |
/** | |
* Rewind the firsts iterators until $position given | |
* | |
* @param int $position | |
*/ | |
protected function rewindIteratorsUntilPosition($position) | |
{ | |
foreach ($this->iterators as $key => $iterator) { | |
if ($key <= $position) { | |
$iterator->rewind(); | |
} | |
} | |
} | |
/** | |
* @inheritdoc | |
*/ | |
public function key() | |
{ | |
return $this->key; | |
} | |
/** | |
* @inheritdoc | |
*/ | |
public function valid() | |
{ | |
$isUnlessOneValid = false; | |
foreach ($this->iterators as $iterator) { | |
if ($iterator->valid()) { | |
$isUnlessOneValid = true; | |
} | |
} | |
return $isUnlessOneValid; | |
} | |
/** | |
* @inheritdoc | |
*/ | |
public function rewind() | |
{ | |
foreach ($this->iterators as $iterator) { | |
$iterator->rewind(); | |
} | |
$this->key = 0; | |
} | |
} |
thank you, no more nested nested nested foreach loops
You may be interested Hoa\Math\Combinatorics\Combination\CartesianProduct
as mentioned in this comment.
Here is the test for the case when the input is empty.
$product = new Hoa\Math\Combinatorics\Combination\CartesianProduct(
['Red', 'White', 'Blue'],
[1, 2, 3, 4],
['Cloth', 'Silk']
);
foreach($product as $i => $tuple)
echo $i, ' = (', implode(', ', $tuple), ')', "\n";
0 = (Red, 1, Cloth)
1 = (White, 1, Cloth)
2 = (Blue, 1, Cloth)
3 = (Red, 2, Cloth)
4 = (White, 2, Cloth)
5 = (Blue, 2, Cloth)
6 = (Red, 3, Cloth)
7 = (White, 3, Cloth)
8 = (Blue, 3, Cloth)
9 = (Red, 4, Cloth)
10 = (White, 4, Cloth)
11 = (Blue, 4, Cloth)
12 = (Red, 1, Silk)
13 = (White, 1, Silk)
14 = (Blue, 1, Silk)
15 = (Red, 2, Silk)
16 = (White, 2, Silk)
17 = (Blue, 2, Silk)
18 = (Red, 3, Silk)
19 = (White, 3, Silk)
20 = (Blue, 3, Silk)
21 = (Red, 4, Silk)
22 = (White, 4, Silk)
23 = (Blue, 4, Silk)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
TODO: