18

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

1
  • 1
    Why don't you use the $keys_to_copy as the main loop? Commented Mar 16, 2012 at 15:43

2 Answers 2

36

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!

Sign up to request clarification or add additional context in comments.

3 Comments

That's the whole purpose of SO: to help others out. Even if you wind up answering your own question. This is the right way to do it.
If you flip the order of your operations, the foreach becomes faster. foreach ($keys_to_copy AS $key) {$copied_data[$key] = $data[$key];}
Up vote from me as it allows for a clean one liner.... This counts more and more these days.
0

Why not load the entire result set into an array, then begin processing with nested loops?

$query_result = mysql_query($my_query) or die(mysql_error());
$query_rows = mysql_num_rows($query_result);
for ($i = 0; $i < $query_rows; $i++)
{
    $row = mysql_fetch_assoc($query_result);
    // 'key' is the name of the column containing the data key (123)
    // 'value' is the name of the column containing the value (aaa)
    $data[$row['key']] = $row['value']; 
}
foreach ($data as $key => $value)
{
    if ( in_array($key, $keys_to_copy)) 
    {
        $copied_data[$key] = $value;
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.