1<?php 2 3/** 4 * Hoa 5 * 6 * 7 * @license 8 * 9 * New BSD License 10 * 11 * Copyright © 2007-2017, Hoa community. All rights reserved. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions are met: 15 * * Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * * Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * * Neither the name of the Hoa nor the names of its contributors may be 21 * used to endorse or promote products derived from this software without 22 * specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE 28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 * POSSIBILITY OF SUCH DAMAGE. 35 */ 36 37namespace Hoa\Math\Combinatorics\Combination; 38 39use Hoa\Iterator; 40 41/** 42 * Class \Hoa\Math\Combinatorics\Combination\CartesianProduct. 43 * 44 * Cartesian n-ary product iterator: 45 * X = {1, 2} 46 * Y = {a, b} 47 * Z = {A, B, C} 48 * X × Y × Z = { (1, a, A), (2, a, A), (1, b, A), (2, b, A) 49 * (1, a, B), (2, a, B), (1, b, B), (2, b, B) 50 * (1, a, C), (2, a, C), (1, b, C), (2, b, C) } 51 * 52 * @copyright Copyright © 2007-2017 Hoa community 53 * @license New BSD License 54 */ 55class CartesianProduct implements Iterator 56{ 57 /** 58 * All sets. 59 * 60 * @var array 61 */ 62 protected $_sets = []; 63 64 /** 65 * Number of sets. 66 * 67 * @var int 68 */ 69 protected $_max = 0; 70 71 /** 72 * Key. 73 * 74 * @var int 75 */ 76 protected $_key = 0; 77 78 /** 79 * Current (contains the current t-uple). 80 * 81 * @var array 82 */ 83 protected $_current = null; 84 85 /** 86 * Whether the iterator has reached the end or not. 87 * 88 * @var bool 89 */ 90 protected $_break = true; 91 92 93 94 /** 95 * Constructor. 96 * 97 * @param \Traversable $set Set. 98 * @param … … … 99 */ 100 public function __construct($set) 101 { 102 foreach (func_get_args() as $s) { 103 if (is_array($s)) { 104 $s = new Iterator\Map($s); 105 } else { 106 $s = new Iterator\IteratorIterator($s); 107 } 108 109 $this->_sets[] = $s; 110 } 111 112 $this->_max = count($this->_sets) - 1; 113 $this->_break = empty($this->_sets); 114 115 return; 116 } 117 118 /** 119 * Get the current value. 120 * 121 * @return array 122 */ 123 public function current() 124 { 125 return $this->_current; 126 } 127 128 /** 129 * Prepare the current value. 130 * 131 * @return void 132 */ 133 protected function _current() 134 { 135 $this->_current = []; 136 137 foreach ($this->_sets as $set) { 138 $this->_current[] = $set->current(); 139 } 140 141 return; 142 } 143 144 /** 145 * Get the current key. 146 * 147 * @return int 148 */ 149 public function key() 150 { 151 return $this->_key; 152 } 153 154 /** 155 * Advance the internal collection pointer, and return the current value. 156 * 157 * @return array 158 */ 159 public function next() 160 { 161 for ($i = 0; $i <= $this->_max; ++$i) { 162 $this->_sets[$i]->next(); 163 164 if (false !== $this->_sets[$i]->valid()) { 165 break; 166 } 167 168 $this->_sets[$i]->rewind(); 169 170 if ($i === $this->_max) { 171 $this->_break = true; 172 173 break; 174 } 175 } 176 177 ++$this->_key; 178 $this->_current(); 179 180 return $this->current(); 181 } 182 183 /** 184 * Rewind the internal collection pointer, and return the first collection. 185 * 186 * @return array 187 */ 188 public function rewind() 189 { 190 $this->_break = empty($this->_sets); 191 $this->_key = 0; 192 193 foreach ($this->_sets as $set) { 194 $set->rewind(); 195 } 196 197 $this->_current(); 198 199 return $this->current(); 200 } 201 202 /** 203 * Check if there is a current element after calls to the rewind() or the 204 * next() methods. 205 * 206 * @return bool 207 */ 208 public function valid() 209 { 210 return false === $this->_break; 211 } 212} 213