Вы могли бы пойти по пути вложения петель foreach
, но что произойдет, если вы захотите расширить снаряжение (например, добавить список связей)? Вот решение, которое выводит комбинации, доступные из любого количества коллекций:
class Combiner {
protected $_collections;
protected $_combinations;
public function __construct() {
$args = func_get_args();
if (count(array_filter(array_map('is_array', $args))) !== func_num_args()) {
throw new Exception('Can only pass array arguments');
}
$this->_collections = $args;
}
protected function _getBatch(array $batch, $index) {
if ($index < count($this->_collections)) {
foreach ($this->_collections[$index] as $element) {
// get combinations of subsequent collections
$this->_getBatch(array_merge($batch, array($element)), $index + 1);
}
} else {
// got a full combination
$this->_combinations[] = $batch;
}
}
public function getCombinations() {
if (null === $this->_combinations) {
$this->_getBatch(array(), 0);
}
return $this->_combinations;
}
}
$hats = array('Hat A', 'Hat B', 'Hat C');
$shirts = array('Shirt A', 'Shirt B', 'Shirt C');
$pants = array('Pants A', 'Pants B', 'Pants C');
$combiner = new Combiner($hats, $shirts, $pants);
var_dump($combiner->getCombinations());
Он перемещается по списку типов и выбирает один (скажем, шляпу A), а затем рекурсивно строит комбинации остальных типов, которые идут с этим элементом. Чтобы добавить новый тип, достаточно просто передать другой аргумент в конструктор.