2013-04-29 31 views
18

我有一个名为Collection的类,它存储相同类型的对象。 Collection实现阵列接口:IteratorArrayAccessSeekableIterator,并Countablearray_map与数组接口的集合?

我想传递一个Collection对象作为数组参数到array_map功能。但这种失败,出现错误

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

我可以通过实施其他/多接口实现这一目标,使Collection对象被看作数组?

+3

推出自己的collection_map功能? – Adder 2013-04-29 08:21:05

+0

@Adder Course我可以,但现在我正在寻找解决方案,如果我可以使用我的集合与buildin php funcs :) – f1ames 2013-04-29 08:28:23

回答

6

array_map想要,顾名思义,阵列。毕竟它不叫iterator_map。 ;)

除了生成一个潜在的大型临时数组的iterator_to_array()之外,没有技巧使得可迭代对象可以使用array_map

Functional PHP库有map实现其在可迭代的收集工作。

+0

功能PHP映射实现不是有效的内存:结果存储在数组中。我找到了一个更好的库:https://github.com/SuRaMoN/itertools还有一篇博客文章解释了如何自己构建它:http://www.a-basketful-of-papayas.net/2012/07/what -adrators-can-do-for-you.html – 2015-07-27 16:33:16

+0

Aad,通常map函数的结果是* new *数组 - 内存开销与方法是固有的,在绝大多数用例中可忽略不计。 – 2016-11-01 19:01:38

+0

“使用'array_map'使可迭代对象工作没有任何窍门。”这个技巧是'iterator_to_array()'。 – 2017-05-12 16:13:42

19

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

这是行不通的,但会有性能损失,因为它会在iterator_to_array步骤中迭代,并且会在array_map步骤中再次迭代。 – 2014-01-30 18:15:40

+1

@EelkevandenBos我在答案中给出了两个解决方案,后者没有展示这种“性能损失”;除此之外,在这两种情况下,运行时间都是O(n)。 – 2014-01-30 23:26:30

2

我想出了以下解决方案:

//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

如果你是而不是有兴趣创建一个新的数组,这是一个函数映射到原始数组,你可以使用foreach循环(因为你实现Iterator)。

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

如果你真的想使用地图,那么我认为你必须实现自己的。我建议做它收集的方法,如:

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

我会问自己,如果你真的想用map或者你真的只是意味着foreach