Что это за зверь: PHP: <? $list = new MultiList; $list->add(new ArrayObject(array(1,4,10))); $list->add(new ArrayObject(array(3,6,7))); $list->add(new ArrayObject(array(2,5,7))); $list->add(new ArrayObject(array(0))); foreach($list as $item) echo $item."\n"; можно управлять сортировкой объявляя свой метод сортировки (по-умолчанию сортировка по возрастанию) важно что бы используемые итераторы были уже отсортировани в том же порядке PHP: <? function myCmpFunction($a, $b) { if ($a == $b) return 0; return $a < $b ? 1 : -1; } $list->setCmpFunction('myCmpFunction'); или используя готовый метод сортировки по атрибуту (если итераторы возращают объект) PHP: <? $list->sortByAttribute('timeAdd'); Собственно сам класс PHP: <? /** * Класс агрегирует несколько итераторов */ class MultiList implements Iterator, Countable { private $collect = array(); private $cmpFunction; private $key; private $currentList; /** * @param Traversable $list * @param Traversable $list * ... */ function __construct() { foreach (func_get_args() as $list) $this->add($list); } /** * @param Traversable $list * * @return MultiList */ function add(Traversable $list) { if ($list instanceof IteratorAggregate) { $list = $list->getIterator(); } if ($list instanceof Countable) { $this->collect[] = $list; } else { throw new Exception('Object not instanceof Countable'); } return $this; } /** * Использовать специфичную функцию для сортировки * * @param mixed $cmpFunction * @return MultiList */ function setCmpFunction($cmpFunction) { if (is_callable($cmpFunction)) { $this->cmpFunction = $cmpFunction; } else { throw new Exception('$cmpFunction is not callable'); } return $this; } private $cmpAttribute; private $cmpAsc; /** * Использовать для сортировки атрибут объекта * * @param string $attribute * @param bool $asc = true */ function sortByAttribute($attribute, $asc = true) { $this->cmpAttribute = $attribute; $this->cmpAsc = $asc; $this->setCmpFunction(array($this, 'cmpAttributeCallback')); } function cmpAttributeCallback($a, $b) { $attribute = $this->cmpAttribute; $a = $a->$attribute; $b = $b->$attribute; if ($a == $b) return 0; $result = $a < $b ? -1 : 1; return $this->cmpAsc ? $result : $result * -1; } function rewind() { foreach ($this->collect as $list) $list->rewind(); $this->key = 0; $this->currentList = null; return $this->current(); } function current() { if ($this->valid()) { return $this->getCurrentList()->current(); } else { return null; } } private function getCurrentList() { if (is_null($this->currentList)) { $values = array(); foreach ($this->collect as $key=>$list) { if ($list->valid()) $values[$key] = $list->current(); } if ($values) { if (is_null($this->cmpFunction)) { asort($values); } else { uasort($values, $this->cmpFunction); } reset($values); $key = key($values); $this->currentList = $this->collect[$key]; } else { $this->currentList = false; } } return $this->currentList; } function next() { if ($this->valid()) { $this->getCurrentList()->next(); $this->key++; } $this->currentList = null; return $this->current(); } function valid() { return (bool) $this->getCurrentList(); } function key() { return $this->key; } function count() { $sum = 0; foreach ($this->collect as $list) $sum += $list->count(); return $sum; } }
Норм, удобное решение, единственное что смущает это вызов функции сортировки при каждом получении очередного элемента. Сколько элементов - столько раз сортировка, годится только для небольших списков. Но концепция хорошая.