Can I set array keys using array functions like array_map

I really like the style of functional programming using an array map to create an array of objects from another array of objects.

$newObjects = array_map( function($oldObject) { return new NewObject($oldObject); }, $oldObjects ); 

That everything works fine, but I would really like to be able to set the indexes of the array so that they are identifiers of the original objects to simplify the search and retrieval from the array, but I can’t think how to do it, then which is not so elegant.

 $newObjects = array(); foreach ($oldObjects as $oldObject) { $newObjects[$oldObject->getId()] = new NewObject($oldObject); } 

Is there any way to do this?

+5
source share
4 answers

That is - array_reduce() is exactly what you need:

 class Bar { protected $id; public function __construct($id) { $this->id = $id; } public function getId() { return $this->id; } } class Foo { protected $bar; public function __construct(Bar $bar) { $this->bar = $bar; } } $oldObjects = [new Bar('x'), new Bar('y'), new Bar('z')]; $newObjects = array_reduce($oldObjects, function($current, Bar $obj) { $current[$obj->getId()] = new Foo($obj); return $current; }, []); 

This will do everything in place without wasting memory on additional arrays, e.g. array_combine()

However, I would suggest using such constructions when they are needed. Using this just because it “looks better” might not be a good idea, since simple loops are more readable in most cases.

+2
source

What if you use array_walk and a temporary array with your new indexes.

  $array = ['A', 'B', 'C', 'D']; $reIndexedTemp = []; array_walk( $array, function ($item, $key) use (&$reIndexedTemp) { // here you can have your logic to assemble your new index $reIndexedTemp[$key + 100] = $item; } ); //$array = $reIndexedTemp; var_dump($array, $reIndexedTemp); 

(without commented line):

 array(4) { [0] => string(1) "A" [1] => string(1) "B" [2] => string(1) "C" [3] => string(1) "D" } array(4) { [100] => string(1) "A" [101] => string(1) "B" [102] => string(1) "C" [103] => string(1) "D" } 
+1
source

I think foreach is probably the most readable solution in this case, but you can use array_map() with array_combine() to achieve what you want. Sort of:

 // empty array to store the old object ids $ids = []; // map over old objects, inheriting $id // from parent scope by reference $objs = array_map(function($oldObject) use (&$ids) { $ids[] = $oldObject->getId(); return new NewObject($oldObject); }, $oldObjects); // combine id and object arrays $newObjects = array_combine($ids, $objs); 

Hope this helps :)

+1
source

Looking around - Looking for the equivalent of array_map for working with keys in associative arrays

Suggests that it can work with array_combine

So, I guess it will be

 $newObjects = array_combine( array_map( function($oldObject) { return $oldObject->getId(); }, $oldObjects ), array_map( function($oldObject) { return new NewObject($oldObject); }, $oldObjects ) ); 

Hmm, probably the best, only this side is swollen, but definitely much more complicated than foreach

0
source

All Articles