Re-map key/value array data in PHP

Published on Mar 19, 2009 by Jamie Munro

I was recently tasked with a situation where I needed to populate about 10 different "Settings" for every user in the current database.

This example is specifically for CakePHP, however, it could easily be used elsewhere.  My goal was the following, I had an array that was key value paired as follows:

array(
 [0] => array(
  'User' => array(
   'id' => 1)
  ),
 [1] => array(
  'User' => array(
   'id' => 2)
  ),
 [2] => array(
  'User' => array(
   'id' => 3)
  ),
 [3] => array(
  'User' => array(
   'id' => 4)
  ),
)

The result I needed was as follows:

array(
 [0] => array(
  'UserSetting' => array(
   'user_id' => 1)
  ),
 [1] => array(
  'UserSetting' => array(
   'user_id' => 2)
  ),
 [2] => array(
  'UserSetting' => array(
   'user_id' => 3)
  ),
 [3] => array(
  'UserSetting' => array(
   'user_id' => 4)
  ),
)

With a few simple lines of code, I was able to quickly and easily achieve this, let me show you how.



First, let me explain that I was dealing with over 100,000 users and I did not want to do a straight loop and update.  I felt too much processing time and memory would be used for this to work well on a production server that was very active.

Instead, using the array_map() function and a custom function performed this process for me extremely quickly and efficiently.

Below is my sample code that I created to test out my function:

...

// get all user ids
$this->User->recursive = -1;
$users = $this->User->find('all', array('fields'=>'id', 'limit' => 10));

$tmp = array_map(array(&$this, 'fix_element'), $users);

var_dump($tmp);

...

function fix_element($elem) {
 return array("UserSetting" => array("user_id" => $elem['User']['id']));
}


The above code passes in the $users array to the fix_element() function that I created.  The whole thing with the &$this is needed because this is inside a CakePHP controller.

The fix_element() function is called once for each element in the array.  I know I know, I said I didn't want to loop through each element, the key to that statement, is that I didn't want to.  I'm letting PHP do it, which is a lot faster than a foreach statement.

The function replaces $elem['User']['id'] with $elem['UserSetting']['user_id'], exactly the result I wanted.

My finish product loops through an array of my 10 different user settings and adds my other keys for my UserSetting array and I call a saveAll() with my entire array of users, once for each setting.

I don't remember exactly how long the code took to run, but it saved over 1,000,000 records in under 5 minutes, probably around the 2 or 3 minute range.

Tags: CakePHP | array | key/value | PHP

Related Posts

blog comments powered by Disqus