Reputation: 4469
I have a method in a class that looks like this;
class SomeClass {
private $hidden = array(....);
/**
* @return array - numeric indexed array in order of $this->hidden.
* Suitable for use by list(var1, var2, ...)
*/
public function getAsList($list = array())
{
return array_values(array_intersect_key($this->hidden, array_flip($list) );
}
But this is not useful, since the caller of the method does not know the order of the key/element pairs in the associative array in instance variable $hidden. Ideally, the returned array would be in the exact same order as the keys specified in $list. For example:
$foo = new SomeClass();
list($foo, $bar, $baz) = $foo->getAsList(array('foo', 'bar', 'baz');
I can easily write some explicit, verbose PHP code in a loop to do this, but is there some clever way to use the various array functions, e.g. array_multisort() to spit this out in minimal lines of code (and hopefully, at compiled code speed -- I'll test it, if it matters).
In a sense, this is a brain teaser to which I don't yet know the answer. It's not critical I do it without an explicit loop, but I'm curious as to if it can be done. I spent 30 or so minutes on it, and haven't found a solution yet.
Upvotes: 14
Views: 2623
Reputation: 47991
This is one of those cases when functional programming pales in comparison to a language construct in terms of readability, maintanability, and efficiency.
I have a bias toward functional programming, but in this case it just doesn't pay.
Code: (Demo)
$hidden = [
'apples' => 19,
'eggs' => 7,
'grapes' => 144,
'mushrooms' => 3,
'oranges' => 16
];
$list = ['grapes', 'apples', 'eggs', 'oranges'];
foreach ($list as $item) {
if (isset($hidden[$item])) {
$result[] = $hidden[$item];
}
}
var_export($result);
Output:
array (
0 => 144,
1 => 19,
2 => 7,
3 => 16,
)
If you insist on using functional programming, then it would be most efficient to perform the required operations in this order:
Here is how:
Code: (Demo)
$flippedList = array_flip($list);
var_export(array_values(array_replace($flippedList, array_intersect_key($hidden, $flippedList))));
(same output as previous snippet)
Logically, it doesn't make sense to order an array that has excess elements in it. Lighten the load, first.
Upvotes: 2
Reputation: 141877
Perhaps array_replace is the missing piece to your puzzle:
public function getAsList($list = array())
{
$klist = array_flip($list);
return array_values(array_intersect_key(array_replace($klist, $this->hidden), $klist));
}
Example (Demo):
$hidden = [
'apples' => 19,
'eggs' => 7,
'grapes' => 144,
'mushrooms' => 3,
'oranges' => 16
];
$list = ['grapes', 'apples', 'eggs', 'oranges'];
$klist = array_flip($list);
print_r(array_values(array_intersect_key(array_replace($klist, $hidden), $klist)));
/*
Array
(
[0] => 144
[1] => 19
[2] => 7
[3] => 16
)
*/
Upvotes: 18