with values keys array_walk array_map array php arrays iterator array-map

php - values - array_map en la colección con interfaces de matriz?



php array_map with keys (5)

Tengo una clase llamada Collection que almacena objetos del mismo tipo. Collection implementa interfaces de matriz: Iterator , ArrayAccess , SeekableIterator y Countable .

Me gustaría pasar un objeto de Collection como el argumento de matriz a la función array_map . Pero esto falla con el error.

Advertencia de PHP: array_map (): Argumento # 2 debe ser una matriz

¿Puedo lograr esto implementando otras / más interfaces, para que los objetos de la Collection se vean como matrices?


La función array_map() no admite un Traversable como su argumento de matriz, por lo que tendría que realizar un paso de conversión:

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

Además de iterar dos veces sobre la colección, también produce una matriz que no se utilizará después.

Otra forma es escribir tu propia función de mapa:

function map(callable $fn) { $result = array(); foreach ($this as $item) { $result[] = $fn($item); } return $result; }

Actualizar

A juzgar por su caso de uso, parece que ni siquiera está interesado en el resultado de la operación del mapa; por lo tanto, tiene más sentido utilizar iterator_apply() .

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


Me topé con esta pregunta y logré convertir la colección en una matriz para que funcionara:

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

descargo de responsabilidad Para la pregunta original, esta podría no ser una opción adecuada, pero encontré la pregunta mientras buscaba resolver un problema que resolví con esta solución. Recomendaría utilizar un mapa de iteradores personalizados cuando sea posible / viable.

Otra opción es hacer algo como esto:

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

que mutará la colección subyacente.


Se me ocurrió la siguiente solución:

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

De esta manera, puede generar una matriz sin iterar dos veces como lo haría con el enfoque como:

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

¡Buena suerte!


Si no está interesado en crear una nueva matriz que sea una función asignada sobre la matriz original, simplemente podría usar un bucle foreach (porque implementa Iterator ).

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

Si realmente quieres usar el mapa, creo que tendrás que implementar el tuyo. Sugeriría convertirlo en un método en Colección, por ejemplo:

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

Me preguntaría si realmente quiere usar el map o si realmente quiere decir foreach


array_map quiere, como su nombre lo indica, matrices . No se llama iterator_map después de todo. ;)

Aparte de iterator_to_array() , que produce una matriz temporal potencialmente grande, no hay truco para hacer que los objetos iterables trabajen con array_map .

La biblioteca funcional de PHP tiene una implementación de map que funciona en cualquier colección iterable.