PHP ленивое отображение массива

Есть ли способ сделать array_map, но как итератор?

Например:

foreach (new MapIterator($array, $function) as $value) { if ($value == $required) break; } 

Причиной этого является то, что $ function сложно вычислить, а $ array имеет слишком много элементов, нужно только сопоставить, пока не найду определенное значение. array_map будет вычислять все значения, прежде чем я смогу найти тот, который я хочу.

Я мог бы сам реализовать итератор, но я хочу знать, есть ли у него собственный способ сделать это. Я не нашел ничего, что могло бы найти в документации по PHP.

Короче: Нет.

В PHP нет ленивого отображения итератора. Существует нелогичная функция iterator_apply () , но ничего похожего на то, что вам нужно.

Как вы сказали, вы могли бы написать его сами. Я предлагаю вам расширить IteratorIterator и просто переопределить метод current () .

Если бы такое было, это было бы задокументировано здесь или здесь .

Это ленивая функция карты коллекции, которая возвращает вам Iterator :

 /** * @param array|Iterator $collection * @param callable $function * @return Iterator */ function collection_map( $collection, callable $function ) { foreach( $collection as $element ) { yield $function( $element ); } } 

Я думаю о простой реализации класса Map, в которой используется массив ключей и массив значений. Общая реализация может быть использована как класс Iterator Java, тогда как вы будете проходить через нее, как:

 while ($map->hasNext()) { $value = $map->next(); ... } 
 foreach ($array as $key => $value) { if ($value === $required) { break; } else { $array[$key] = call_back_function($value); } } 

процесс и итерацию до тех пор, пока не будет найдено требуемое значение.

Не беспокойтесь об итераторе, это ответ:

 foreach ($array as $origValue) { $value = $function($origValue); if ($value == $required) break; } 

Я написал этот класс для использования обратного вызова для этой цели. Применение:

 $array = new ArrayIterator(array(1,2,3,4,5)); $doubles = new ModifyIterator($array, function($x) { return $x * 2; }); 

Определение (не стесняйтесь изменять для своих нужд):

 class ModifyIterator implements Iterator { /** * @var Iterator */ protected $iterator; /** * @var callable Modifies the current item in iterator */ protected $callable; /** * @param $iterator Iterator|array * @param $callable callable This can have two parameters * @throws Exception */ public function __construct($iterator, $callable) { if (is_array($iterator)) { $this->iterator = new ArrayIterator($iterator); } elseif (!($iterator instanceof Iterator)) { throw new Exception("iterator must be instance of Iterator"); } else { $this->iterator = $iterator; } if (!is_callable($callable)) { throw new Exception("callable must be a closure"); } if ($callable instanceof Closure) { // make sure there's one argument $reflection = new ReflectionObject($callable); if ($reflection->hasMethod('__invoke')) { $method = $reflection->getMethod('__invoke'); if ($method->getNumberOfParameters() !== 1) { throw new Exception("callable must have only one parameter"); } } } $this->callable = $callable; } /** * Alters the current item with $this->callable and returns a new item. * Be careful with your types as we can't do static type checking here! * @return mixed */ public function current() { $callable = $this->callable; return $callable($this->iterator->current()); } public function next() { $this->iterator->next(); } public function key() { return $this->iterator->key(); } public function valid() { return $this->iterator->valid(); } public function rewind() { $this->iterator->rewind(); } } 

Итераторы PHP довольно громоздки в использовании, особенно если требуется глубокое вложение. LINQ, который реализует SQL-подобные запросы для массивов и объектов, лучше подходит для этого, поскольку он позволяет легко связывать методы и лениться через них. Одна из библиотек, реализующих его, – YaLinqo *. С его помощью вы можете выполнять картографирование и фильтрацию следующим образом:

 // $array can be an array or \Traversible. If it's an iterator, it is traversed lazily. $is_value_in_array = from($array)->contains(2); // where is like array_filter, but lazy. It'll be called only until the value is found. $is_value_in_filtered_array = from($array)->where($slow_filter_function)->contains(2); // select is like array_map, but lazy. $is_value_in_mapped_array = from($array)->select($slow_map_function)->contains(2); // first function returns the first value which satisfies a condition. $first_matching_value = from($array)->first($slow_filter_function); // equivalent code $first_matching_value = from($array)->where($slow_filter_function)->first(); 

Есть еще много функций, более 70 в целом.

* разработан мной

Посмотрите на нестандартную библиотеку PHP . Он имеет ленивую функцию карты :

 use function \nspl\a\lazy\map; $heavyComputation = function($value) { /* ... */ }; $iterator = map($heavyComputation, $list);