PHP multidimensional array: replace all keys with concatenation of two values

I have a multidimensional array in PHP, where the external array contains several thousand elements, and each element inside is the array itself with the values ​​"key1", "key2" and "count":

myExistingArray (size=99999 VERY BIG) public 0 => array (size=3) 'key1' => string '15504' 'key2' => string '20' 'count' => string '1' public 1 => array (size=3) 'key1' => string '15508' (length=5) 'key2' => string '20' (length=2) 'count' => string '2' (length=1) public 2 => array (size=3) 'key1' => string '15510' (length=5) 'key2' => string '20' (length=2) 'count' => string '5' (length=1) ....many more similar items 

I want to convert this to a very simple array, where the old values ​​from "key1" and "key" are combined as a new key that points to the "count" value for corresspond:

  myNewArray (size=99999 VERY BIG) <key1>_<key2> => <count> 15504_20 => string '1' (length=1) 15508_20 => string '2' (length=1) 15510_20 => string '5' (length=1) 

Performance is very important to me, since the external array has several thousand elements. Is there a quick method in PHP? The only thing I had was a simple iteration, but for me it gets in the way:

 // works but I am looking for a faster version $myNewArray = array(); foreach ($myExistingArray as $item) { $myNewArray [$item["key1"]."_".$item["key1"]]=$item["count"]; } 

EDIT / Main Problem

Some people rightfully added that my current solution is already in O (n) and it is mentioned that there is no built-in function in PHP to speed this up.

I get "myExistingArray" from the mysql database query. I basically have job objects and want to group them by their status and their event_id. The request is similar to this:

 select count(job.id) as count, job.status as key1, job.event_id as key2 from job group by job.status, job.event_id 

I want to change the order of the keys so that later I can easily access the job account for a specific event with a certain status.

+7
arrays php multidimensional-array
source share
4 answers

Usually you are looking for either array_walk or array_map to convert arrays to PHP, but, unfortunately, none of them can change the key of the array you want to convert. array_walk save the keys, but will not change them. Unfortunately, no, there is no built-in function to do what you ask.

+2
source share

I did some tests with the following results (almost anyway).

 Test 1: [0.25861501693726] Test 2: [0.20804476737976] Test 3: [0.21039199829102] Oldskool:[0.26545000076294] Test 4: [0.35072898864746] 

Running var_dump() in a merged array slows down (as expected), but if you store it in memory, the data is not so bad for work.

And PHP used for testing:

 // Construct the raw data $i = 0; do { $raw[] = array('key1' => mt_rand(10000,99999), 'key2' => mt_rand(10,99), 'count' => $i); } while(++$i < 100000); // Test 1 $before = microtime(true); foreach($raw as $k => $v) { $clean[$v['key1'].'_'.$v['key2']] = $v['count']; } $after = microtime(true); echo 'Test 1:['.($after - $before).']<br />'; $clean = false; $i = 0; // Test 2 $before = microtime(true); $max = count($raw); do { $clean[$raw[$i]['key1'].'_'.$raw[$i]['key2']] = $raw[$i]['count']; } while(++$i < $max); $after = microtime(true); echo 'Test 2:['.($after - $before).']<br />'; $clean = false; $i = 0; // Test 3 $before = microtime(true); $max = count($raw); for($i; $i < $max; $i++) { $clean[$raw[$i]['key1'].'_'.$raw[$i]['key2']] = $raw[$i]['count']; } $after = microtime(true); echo 'Test 3:['.($after - $before).']<br />'; $clean = false; // Test of Oldskool suggestion $before = microtime(true); foreach (array_keys($raw) as $item) { $clean[$raw[$item]['key1'].'_'.$raw[$item]['key2']] = $raw[$item]['count']; } $after = microtime(true); echo 'Test Oldskool:['.($after - $before).']<br />'; $clean = false; $i = 0; // Test 4, just for fun $before = microtime(true); $max = count($raw); do { $c = array_pop($raw[$i]); $clean[join('_', $raw[$i])] = $c; } while(++$i < $max); $after = microtime(true); echo 'Test 4:['.($after - $before).']<br />'; 

Edit : Added test for Oldskool example.

+1
source share

You can change your foreach to iterate over keys only, and not all subarrays by changing them to:

 foreach (array_keys($myExistingArray) as $item) { $myNewArray[$myExistingArray[$item]['key1'] . '_' . $myExistingArray[$item]['key2']] = $myExistingArray[$item]['count']; } 

This will give you a slight speed advantage (see a comparison of times here (array_keys method) and here (your original method)). On very large arrays, the difference is likely to become more noticeable.

0
source share

If speed is a problem, and you are not using the last array as a map, I would create a generator, so you do not need to calculate everything beforehand.

 $myExistingArray = [ ... ]; class MyNewArrayIterator implements IteratorAggregate { protected $array; public function __construct(array $array) { $this->array = $array; } public function getIterator() { foreach ($this->array as $value) { yield $value['key1'] . '_' . $value['key2'] => $value['count']; } } } 

And then you can do:

 $myNewArray = new MyNewArrayIterator($myExistingArray); foreach($myNewArray as $key => $value) { echo $key . ": " . $value; } 

This may or may not be useful in your use case.

0
source share

All Articles