Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP sorting array_intersect_key() results by second array

Tags:

php

sorting

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.

like image 329
CXJ Avatar asked Jul 03 '13 00:07

CXJ


2 Answers

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
)
*/
like image 171
Paul Avatar answered Sep 22 '22 03:09

Paul


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:

  • filter the array
  • order the keys of the filtered array
  • reindex the ordered, filtered array

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.

like image 35
mickmackusa Avatar answered Sep 25 '22 03:09

mickmackusa