PHP懒惰数组映射

时间:2011-07-03 23:11:55

标签: php spl

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

例如:

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

这样做的原因是$ function很难计算,而$ array有太多元素,只需映射直到找到特定值。 array_map将在我搜索我想要的值之前计算所有值。

我可以自己实现迭代器,但我想知道是否有本地方法来执行此操作。我找不到任何搜索PHP文档的内容。

8 个答案:

答案 0 :(得分:6)

简而言之:否。

PHP中没有内置的延迟迭代器映射。有一个非惰性函数 iterator_apply(),但没有你喜欢的那样。

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

如果有这样的事情,则要记录herehere

答案 1 :(得分:5)

这是一个懒惰的集合地图函数,可以返回Iterator

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

答案 2 :(得分:1)

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

一样遍历它
while ($map->hasNext()) {
  $value = $map->next();
  ...
}

答案 3 :(得分:0)

foreach ($array as $key => $value) {
   if ($value === $required) {
      break;
   } else {
      $array[$key] = call_back_function($value);
   }
}

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

答案 4 :(得分:0)

请勿使用迭代器,答案是:

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

答案 5 :(得分: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();
    }
}

答案 6 :(得分: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种。

*由我开发

答案 7 :(得分:0)

看看Non-standard PHP library。它有一个lazy map函数:

use function \nspl\a\lazy\map;

$heavyComputation = function($value) { /* ... */ };
$iterator = map($heavyComputation, $list);