1
\$\begingroup\$

I have been trying to parse results and make sure when I am doing so that I don't repeat the same data. I tried to use a few different options built into php with no luck. I did find an example of a recursive array search that seems to work but it's very intensive and adds a lot of time to the script.

What I'm needing: Does anyone know a better way to handle this without changing the array that I supply to it so something built-in like in_array or array_search?

Array example:

array (size=3)
  0 => 
    array (size=3)
      'author' => string 'Jim Beam' (length=8)
      'id' => string '1' (length=1)
      'md5' => string 'f2ebf4d4f333c31ef1491a377edf2cc4' (length=32)
  1 => 
    array (size=3)
      'author' => string 'Jack Daniels' (length=12)
      'id' => string '2' (length=1)
      'md5' => string 'd1839707c130497bfd569c77f97ccac7' (length=32)
  2 => 
    array (size=3)
      'author' => string 'Jose Cuervo' (length=11)
      'id' => string '3' (length=1)
      'md5' => string '64e989b4330cc03dea7fdf6bfe10dda1' (length=32)

Code example:

function recursive_array_search($needle,$haystack) {
    foreach($haystack as $key=>$value) {
        $current_key=$key;
        if($needle===$value OR (is_array($value) && recursive_array_search($needle,$value) !== false)) {
            return $current_key;
        }
    }
    return false;
}

$agentArray = array(
    array('author'=>'Jim Beam','id'=>'1','md5'=>'f2ebf4d4f333c31ef1491a377edf2cc4'),
    array('author'=>'Jack Daniels','id'=>'2','md5'=>'d1839707c130497bfd569c77f97ccac7'),
    array('author'=>'Jose Cuervo','id'=>'3','md5'=>'64e989b4330cc03dea7fdf6bfe10dda1')
);

$fakeMD5 = '84d7dc19766c446f5e4084e8fce87f82'; //StackOverflow MD5
$realMD5 = 'd1839707c130497bfd569c77f97ccac7'; //Jack Daniels MD5

echo '<b>In_Array:</b> <br/>';

$faketest = in_array($fakeMD5,$agentArray);
$realtest = in_array($realMD5,$agentArray);

var_dump($faketest,$realtest);

echo '<b>Search_Array:</b> <br/>';

$faketest2 = array_search($fakeMD5,$agentArray);
$realtest2 = array_search($realMD5,$agentArray);

var_dump($faketest2,$realtest2);

echo '<b>Custom Recursive Array Seach Function:</b> <br/>';

$faketest3 = recursive_array_search($fakeMD5,$agentArray);
$realtest3 = recursive_array_search($realMD5,$agentArray);

var_dump($faketest3,$realtest3);

Results:

In_Array:
Fake: boolean false
Real: boolean false

Search_Array:
Fake: boolean false
Real: boolean false

Custom Recursive Array Seach Function:
Fake: boolean false
Real: int 1
\$\endgroup\$
  • 1
    \$\begingroup\$ Also for PHP 5.5+ there is a simpler option, array_search($value, array_column($array, $key)); see stackoverflow.com/a/24527099/207603 (there is also a link to a backport for < PHP 5.5) \$\endgroup\$ – Radu Maris Jan 22 '15 at 9:38
1
\$\begingroup\$

I have two comments.

First, what is the purpose of $current_key? Since you're not changing it, just use $key.

Second, by your usage, I'd say that

foreach ($haystack as $key => $item)
    if ($item["md5"] === $needle) return $key;
return false;

is quite enough. Of course, if the above was just an example and you really want to check all the values in (sub)arrays, then the above is O.K.

Of course, be careful when using this function, because key 0 may be interpreted as false.

A bit neater (but essentially the same) function was provided on Stack Overflow here. I like the additional $strict argument there (which you may or may not need).

\$\endgroup\$
  • \$\begingroup\$ Yeah thats not my function someone added that in a different thread but I think I overlooked the simplicity of my operation. I will use your example and see if its faster! \$\endgroup\$ – sin0cide Aug 23 '13 at 22:25
1
\$\begingroup\$

I will echo what Radu posted as a comment. I find a combination of array_search() with array_column() to be concise and easy to read. While foreach loops can perform slightly faster, using purpose-built native php functions can improve comprehension based on their names. Lines of code are reduced as well, if that is important to you, because array_search() bundles the array iteration, condition statement, and the return/break tasks.

Code: (Demo)

$agentArray = array(
    array('author'=>'Jim Beam','id'=>'1','md5'=>'f2ebf4d4f333c31ef1491a377edf2cc4'),
    array('author'=>'Jack Daniels','id'=>'2','md5'=>'d1839707c130497bfd569c77f97ccac7'),
    array('author'=>'Jose Cuervo','id'=>'3','md5'=>'64e989b4330cc03dea7fdf6bfe10dda1')
);

$fakeMD5 = '84d7dc19766c446f5e4084e8fce87f82'; //StackOverflow MD5
$realMD5 = 'd1839707c130497bfd569c77f97ccac7'; //Jack Daniels MD5

echo 'StackOverflow MD5 result: ';
var_export(array_search($fakeMD5,array_column($agentArray,'md5'),true));  // returns false : not found

echo "\nJack Daniels MD5 result: ";
var_export(array_search($realMD5,array_column($agentArray,'md5'),true));  // returns 1 : offset of the subarray

Output:

StackOverflow MD5 result: false
Jack Daniels MD5 result: 1

Now some notes about "strict" / "indentical" searching and the search results:

  • I have included the third parameter true to the array_search() function. This is important if the needle ($xxxxMD5) comes from an untrustworthy source (e.g. user input). The reason is because if you omit the parameter then php will do a loose comparison and use "type juggling" (a post of mine with manual references and a demo). A loose comparison when the needle is 0 will return the Jim Beam subarray's offset, and this is likely to be an unintended result.

  • Similarly, when you are processing the result from the multidimensional search, take the same care to differentiate between a false and a 0 result. Like with strpos() it is best perform a strict comparison like !==false or ===false depending on your usage.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.