15

有没有办法做 array_map 但作为迭代器?

例如:

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

这样做的原因是 $function 很难计算并且 $array 元素太多,只需要映射直到找到特定值。array_map 将计算所有值,然后才能搜索我想要的值。

我可以自己实现迭代器,但我想知道是否有这样做的本机方式。我找不到任何搜索 PHP 文档的内容。

4

8 回答 8

6

简而言之:没有。

PHP 中没有内置惰性迭代器映射。有一个非惰性函数iterator_apply(),但与您所追求的完全不同。

正如你所说,你可以自己写一个。我建议您扩展IteratorIterator并简单地覆盖current()方法。

如果有这样的事情,它会记录在这里这里

于 2011-07-04T08:38:40.427 回答
6

这是一个惰性集合映射函数,可以返回Iterator

/**
 * @param array|Iterator $collection
 * @param callable $function
 * @return Iterator
 */
function collection_map( $collection, callable $function ) {
    foreach( $collection as $element ) {
        yield $function( $element );
    }
}
于 2015-08-19T15:03:19.240 回答
1

我正在考虑一个简单的 Map 类实现,它使用一个键数组和一个值数组。整体实现可以像 Java 的 Iterator 类一样使用,而您可以像这样迭代它:

while ($map->hasNext()) {
  $value = $map->next();
  ...
}
于 2011-07-03T23:15:48.317 回答
0
foreach ($array as $key => $value) {
   if ($value === $required) {
      break;
   } else {
      $array[$key] = call_back_function($value);
   }
}

处理和迭代,直到找到所需的值。

于 2011-07-04T03:23:43.173 回答
0

不要打扰迭代器,答案是:

foreach ($array as $origValue)
{
   $value = $function($origValue);
   if ($value == $required)
      break;
}
于 2012-04-17T18:37:45.680 回答
0

为此,我编写了这个类来使用回调。用法:

$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();
    }
}
于 2014-07-09T21:12:04.900 回答
0

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 个。

* 由我开发

于 2015-06-04T15:24:59.767 回答
0

看看非标准 PHP 库。它有一个惰性映射功能:

use function \nspl\a\lazy\map;

$heavyComputation = function($value) { /* ... */ };
$iterator = map($heavyComputation, $list);
于 2017-02-03T21:01:32.357 回答