使用
class CartesianProductIterator implements Iterator {
protected $iterators;
function __construct(array $iters) {
$this->iterators = $iters;
}
function rewind() {
foreach ($this->iterators as $it) {
$it->rewind();
}
}
function current() {
$values = array();
foreach ($this->iterators as $it) {
$values[] = $it->current();
}
return $values;
}
function key() {
return null;
}
function next() {
/*
loop them in reverse, but exclude first
why? example, odometer: 55199
you always check the rightmost digit first to see if incrementing it would roll it over and need to be "rewound" to 0,
which causes the digit to the left to increase as well, which may also cause it to roll over as well, and so on...
looping in reverse operates from right column to the left.
we dont rewind the first column because if the leftmost column is on its last element and needs to roll over
then this iterator has reached its end, and so rewind() needs to be explicitly called
*/
for ($i = count($this->iterators) - 1; $i > 0; --$i) {
$it = $this->iterators[$i];
$it->next();
if ($it->valid()) {
// were done advancing because we found a column that didnt roll over
return;
} else {
$it->rewind();
}
}
//if execution reached here, then all of the columns have rolled over, so we must attempt to roll over the left most column
$this->iterators[0]->next();
}
function valid() {
return $this->iterators[0]->valid();
}
}
您可以按如下方式专门使用它
$iterators = array();
foreach ($arr as $possibleChoicesForOneSlotInACombo) {
//we add null as a way indicate "no value" as a choice for this slot
$possibleChoicesForOneSlotInACombo[] = null;
$iterators[] = new ArrayIterator($possibleChoicesForOneSlotInACombo);
}
foreach (new CartesianProductIterator($iterators) as $combo) {
//filter out the possible nulls that might exist in this combo
$strings = array_filter($combo, 'is_string');
// make sure something exists, maybe they were all null
if ($strings) {
echo join(' ', $strings), "\n";
}
}