Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP array copy certain keys, built-in functions? Nested loop performance?

Tags:

arrays

php

I have a PHP array that I'd like to duplicate but only copy elements from the array whose keys appear in another array.

Here are my arrays:

$data[123] = 'aaa';
$data[423] = 'bbb';
$data[543] = 'ccc';
$data[231] = 'ddd';
$data[642] = 'eee';
$data[643] = 'fff';
$data[712] = 'ggg';
$data[777] = 'hhh';

$keys_to_copy[] = '123';
$keys_to_copy[] = '231';
$keys_to_copy[] = '643';
$keys_to_copy[] = '712';
$keys_to_copy[] = '777';

$copied_data[123] = 'aaa';
$copied_data[231] = 'ddd';
$copied_data[643] = 'fff';
$copied_data[712] = 'ggg';
$copied_data[777] = 'hhh';

I could just loop through the data array like this:

foreach ($data as $key => $value) {
  if ( in_array($key, $keys_to_copy)) {
    $copied_data[$key] = $value;
  }
}

But this will be happening inside a loop which is retrieving data from a MySQL result set. So it would be a loop nested within a MySQL data loop. I normally try and avoid nested loops unless there's no way of using PHP's built-in array functions to get the result I'm looking for. But I'm also weary of having a nested loop within a MySQL data loop, I don't want to keep MySQL hanging around.

I'm probably worrying about nested loop performance unnecessarily as I'll never be doing this for more than a couple of hundred rows of data and maybe 10 keys.

But I'd like to know if there's a way of doing this with built-in PHP functions.
I had a look at array_intesect_key() but that doesn't quite do it, because my $keys_to_copy array has my desired keys as array values rather than keys.

Anyone got any ideas?

Cheers, B

like image 645
batfastad Avatar asked Mar 16 '12 15:03

batfastad


1 Answers

I worked it out - I almost had it above.I thought I'd post the answer anyway for completeness. Hope this helps someone out!

array_intersect_key($data, array_flip($keys_to_copy))

Use array_flip() to switch $keys_to_copy so it can be used within array_intersect_keys()

I'll run some tests to compare performance between the manual loop above, to this answer. I would expect the built-in functions to be faster but they might be pretty equal. I know arrays are heavily optimised so I'm sure it will be close.

EDIT:
I have run some benchmarks using PHP CLI to compare the foreach() code in my question with the code in my answer above. The results are quite astounding.
Here's the code I used to benchmark, which I think is valid:

<?php
ini_set('max_execution_time', 0);//NOT NEEDED FOR CLI

// BUILD RANDOM DATA ARRAY
$data = array();
while ( count($data) <= 200000) {
    $data[rand(0, 500000)] = rand(0, 500000);
}
$keys_to_copy = array_rand($data, 100000);

// FOREACH
$timer_start = microtime(TRUE);
foreach ($data as $key => $value) {
    if ( in_array($key, $keys_to_copy)) {
        $copied_data[$key] = $value;
    }
}
echo 'foreach: '.(microtime(TRUE) - $timer_start)."s\r\n";

// BUILT-IN ARRAY FUNCTIONS
$timer_start = microtime(TRUE);
$copied_data = array_intersect_key($data, array_flip($keys_to_copy));
echo 'built-in: '.(microtime(TRUE) - $timer_start)."s\r\n";
?>

And the results...
foreach: 662.217s
array_intersect_key: 0.099s

So it's much faster over loads of array elements to use the PHP array functions rather than foreach. I thought it would be faster but not by that much!

like image 77
batfastad Avatar answered Sep 19 '22 20:09

batfastad