1

Let's say I've got an array of objects from class Users. Class Users contain the property email. How can I make an array of the email property from the array of user objects?

Is there a better/faster way than:

$emails = array();
foreach($users as $user) {
   $emails[] = $user->email;
}

2 Answers 2

3

You can use array_map which will do the looping in C but require calling back to PHP for each iteration.

$emails = array_map(function ($user) { return $user->email; }, $users);

Better?

The above code is more expressive to me and probably most functional programmers, but that's subjective. It also requires PHP 5.3 for the callback. You can get around that for PHP 5.2 and below by declaring a global function, but then you lose much of the clarity, especially when the code appears in a class.

function getUserEmail($user) { return $user->email; }
$emails = array_map('getUserEmail', $users);

Faster?

In this simple case with the callback, it seems to be slower (see Esben's answer). However, I have two caveats here.

  1. Micro-benchmarks are notoriously finicky. They vary from machine to machine and depend on the particular build of the interpreter. But worse, measuring such a small value can be overshadowed by other tasks such as processor multitasking, memory management, etc. The times also varied considerably between using the callback versus the global function.

  2. Developer time is far costlier than CPU cycles. You're better off writing the easiest-to-code and maintain solution first and only optimizing it once you've a) found it to be a problem and b) measured how much of a problem it is. Obviously this is much less important for this simple case, but it's a general rule I've learned to follow.

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

7 Comments

Funny, not on my computer. Just did a benchmark test, and it turns out with 2000 user objects, it looks like this: The benchmark "arrMap (2)" took 1.2409687042236 miliseconds The benchmark "foreach (2)" took 0.43201446533203 miliseconds
similar to map {} @array in perl and collect in SmallTalk
@EsbenTind - As with most micro-benchmarks, it varies a lot with the specific case. Accessing a simple public property like this is faster with foreach, but when I switch to calling a function, array_map is faster. Either way, unless there is a significant performance improvement to foreach, I prefer the more expressive array_map.
The OP describes a pretty basic functionallity. Extracting all email adresses from an array. According to my test, it takes less than half the time to do this with foreach. You save more than 50%. I would agree it really doesn't matter, as we probably aren't going to have this many user objects. But saying that my response is false, is not true in this case. Not in my envoirenment anyways.
@EsbenTind - The OP asked for a "better/faster way." Your answer reads as if there is definitively no other way which is incorrect. If you edit that part out of your answer, I'm happy to remove my downvote.
|
0

Looks like a foreach loop is the fastest. Syntax is a matter of taste, I guess.

EDIT

As I said in my response to David's post, I have in fact benchmarked this.

for($i = 0;$i<=8000;$i++){
    $users[] = (object)array("email"=>rand(0,15));
}

$arrMapBm = new nzpBM("arrMap");
$foreachBm = new nzpBM("foreach");

$arrMapBm->start();
$emails = array_map(function ($user) { return $user->email; }, $users);
echo $arrMapBm;
unset($emails);

$foreachBm->start();
foreach($users as $user) {
   $emails[] = $user->email;
}
echo $foreachBm;

Gives pretty solid results.

The benchmark "arrMap (1)" took 4.8160552978516 miliseconds
The benchmark "foreach (1)" took 2.1059513092041 miliseconds

I don't know if this is because I am on a windows machine at the moment, but for me, array_map is definetedly NOT faster. Not trying to mislead anyone here.

6 Comments

Try it with a global function: function getUserEmail($user) { return $user->email; } and array_map('getUserEmail', $users). Micro-benchmarks are notoriously fickle. :)
Even worse: The benchmark "arrMap (1)" took 7.3180198669434 miliseconds The benchmark "foreach (1)" took 1.9690990447998 miliseconds On 8000 objects
I'm curious if you get the same results with this gist. Running on my Xubuntu development machine I get foreach faster with the callback and array_map faster using the global function. Even though the callback is faster than the function for array_map.
Run foreach took 5.650 ms Run array_map took 11.492 ms, that's with the global function reference.
For the code I posted, on our Core2 Duo Ubuntu server the times are very close. foreach took 12.056 (callback) and 14.391 (function) while array_map took 12.340 (callback slower) and 14.267 (function faster). The order matters, too. Whichever goes first takes slightly longer than the other way around because it has to allocate the memory to the process while the second version gets to reuse that freed memory.
|

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.