有数组接口的集合上的array_map?

时间:2013-04-29 07:23:06

标签: php arrays iterator array-map

我有一个名为Collection的类,它存储相同类型的对象。 Collection实现了数组接口:IteratorArrayAccessSeekableIteratorCountable

我想将Collection对象作为数组参数传递给array_map函数。但这失败了,错误

  

PHP警告:array_map():参数#2应该是一个数组

我可以通过实现其他/更多接口来实现这一点,以便将Collection个对象视为数组吗?

5 个答案:

答案 0 :(得分:25)

array_map()函数不支持Traversable作为其数组参数,因此您必须执行转换步骤:

array_map($fn, iterator_to_array($myCollection));

除了遍历集合两次之外,它还会生成一个之后不会使用的数组。

另一种方法是编写自己的地图功能:

function map(callable $fn)
{
    $result = array();

    foreach ($this as $item) {
        $result[] = $fn($item);
    }

    return $result;
}

<强>更新

根据您的用例判断,您似乎对地图操作的结果不感兴趣;因此使用iterator_apply()更有意义。

iterator_apply($myCollection, function($obj) {
    $obj->method1();
    $obj->method2();

    return true;
});

答案 1 :(得分:7)

顾名思义,

array_map想要数组。毕竟它不叫iterator_map。 ;)

除了产生可能很大的临时数组的iterator_to_array()之外,没有办法让可迭代对象与array_map一起工作。

Functional PHP库有map实现,适用于任何可迭代集合。

答案 2 :(得分:3)

我提出了以下解决方案:

//lets say you have this iterator
$iterator = new ArrayIterator(array(1, 2, 3));

//and want to append the callback output to the following variable
$out = [];

//use iterator to apply the callback to every element of the iterator
iterator_apply(
    $iterator,
    function($iterator, &$out) {
        $current = $iterator->current();
        $out[] = $current*2;
        return true;
    },
    array($iterator, &$out) //arguments for the callback
);

print_r($out);

这样,您可以生成一个数组,而无需像以下方法那样迭代两次:

$iterator = new ArrayIterator(array(1,2,3));
$array = iterator_to_array($iterator); //first iteration
$output = array_map(function() {}, $array); //second iteration
祝你好运!

答案 3 :(得分:3)

如果您对创建一个映射到原始数组的函数的新数组感兴趣,则可以使用foreach循环(因为您实现了Iterator

foreach($item in $myCollection) {
    $item->method1();
    $item->method2();
}

如果您真的想使用地图,那么我认为您必须实施自己的地图。我建议将它作为Collection的方法,例如:

$mutatedCollection = $myCollection->map(function($item) { 
    /* do some stuff to $item */
    return $item;
});

我会问你自己是否真的想使用map或者你真的只是想foreach

答案 4 :(得分:-1)

我偶然发现了这个问题,并设法将集合转换为数组以使其起作用:

array_map($cb, (array) $collection);

免责声明对于最初的问题,这可能不是一个合适的选择,但我在寻找解决该问题的方法时发现了该问题。我建议在可能/可行的情况下使用自定义迭代器映射。

另一种选择是执行以下操作:

foreach($collection as &$item) {
    $item = $cb($item);
}

这将使基础集合发生变异。

编辑:

已经指出,强制转换为数组会产生有害的副作用。最好在集合中添加一个方法以从迭代器返回数组,然后遍历该方法,或者添加一个map方法来接受回调并在基础迭代器上运行循环。