How to search by key=>value in a multidimensional array in PHP

前端 未结 15 2043
闹比i
闹比i 2020-11-22 00:13

Is there any fast way to get all subarrays where a key value pair was found in a multidimensional array? I can\'t say how deep the array will be.

Simple example arra

相关标签:
15条回答
  • 2020-11-22 00:49

    I needed something similar, but to search for multidimensional array by value... I took John example and wrote

    function _search_array_by_value($array, $value) {
            $results = array();
            if (is_array($array)) {
                $found = array_search($value,$array);
                if ($found) {
                    $results[] = $found;
                }
                foreach ($array as $subarray)
                    $results = array_merge($results, $this->_search_array_by_value($subarray, $value));
            }
            return $results;
        }
    

    I hope it helps somebody :)

    0 讨论(0)
  • 2020-11-22 00:51

    How about the SPL version instead? It'll save you some typing:

    // I changed your input example to make it harder and
    // to show it works at lower depths:
    
    $arr = array(0 => array('id'=>1,'name'=>"cat 1"),
                 1 => array(array('id'=>3,'name'=>"cat 1")),
                 2 => array('id'=>2,'name'=>"cat 2")
    );
    
    //here's the code:
    
        $arrIt = new RecursiveIteratorIterator(new RecursiveArrayIterator($arr));
    
     foreach ($arrIt as $sub) {
        $subArray = $arrIt->getSubIterator();
        if ($subArray['name'] === 'cat 1') {
            $outputArray[] = iterator_to_array($subArray);
        }
    }
    

    What's great is that basically the same code will iterate through a directory for you, by using a RecursiveDirectoryIterator instead of a RecursiveArrayIterator. SPL is the roxor.

    The only bummer about SPL is that it's badly documented on the web. But several PHP books go into some useful detail, particularly Pro PHP; and you can probably google for more info, too.

    0 讨论(0)
  • 2020-11-22 00:51
    $result = array_filter($arr, function ($var) {   
      $found = false;
      array_walk_recursive($var, function ($item, $key) use (&$found) {  
        $found = $found || $key == "name" && $item == "cat 1";
      });
      return $found;
    });
    
    0 讨论(0)
  • 2020-11-22 00:54

    Code:

    function search($array, $key, $value)
    {
        $results = array();
    
        if (is_array($array)) {
            if (isset($array[$key]) && $array[$key] == $value) {
                $results[] = $array;
            }
    
            foreach ($array as $subarray) {
                $results = array_merge($results, search($subarray, $key, $value));
            }
        }
    
        return $results;
    }
    
    $arr = array(0 => array(id=>1,name=>"cat 1"),
                 1 => array(id=>2,name=>"cat 2"),
                 2 => array(id=>3,name=>"cat 1"));
    
    print_r(search($arr, 'name', 'cat 1'));
    

    Output:

    Array
    (
        [0] => Array
            (
                [id] => 1
                [name] => cat 1
            )
    
        [1] => Array
            (
                [id] => 3
                [name] => cat 1
            )
    
    )
    

    If efficiency is important you could write it so all the recursive calls store their results in the same temporary $results array rather than merging arrays together, like so:

    function search($array, $key, $value)
    {
        $results = array();
        search_r($array, $key, $value, $results);
        return $results;
    }
    
    function search_r($array, $key, $value, &$results)
    {
        if (!is_array($array)) {
            return;
        }
    
        if (isset($array[$key]) && $array[$key] == $value) {
            $results[] = $array;
        }
    
        foreach ($array as $subarray) {
            search_r($subarray, $key, $value, $results);
        }
    }
    

    The key there is that search_r takes its fourth parameter by reference rather than by value; the ampersand & is crucial.

    FYI: If you have an older version of PHP then you have to specify the pass-by-reference part in the call to search_r rather than in its declaration. That is, the last line becomes search_r($subarray, $key, $value, &$results).

    0 讨论(0)
  • 2020-11-22 00:56

    Came back to post this update for anyone needing an optimisation tip on these answers, particulary John Kugelman's great answer up above.

    His posted function work fine but I had to optimize this scenario for handling a 12 000 row resultset. The function was taking an eternal 8 secs to go through all records, waaaaaay too long.

    I simply needed the function to STOP searching and return when match was found. Ie, if searching for a customer_id, we know we only have one in the resultset and once we find the customer_id in the multidimensional array, we want to return.

    Here is the speed-optimised ( and much simplified ) version of this function, for anyone in need. Unlike other version, it can only handle only one depth of array, does not recurse and does away with merging multiple results.

    // search array for specific key = value
    public function searchSubArray(Array $array, $key, $value) {   
        foreach ($array as $subarray){  
            if (isset($subarray[$key]) && $subarray[$key] == $value)
              return $subarray;       
        } 
    }
    

    This brought down the the task to match the 12 000 records to a 1.5 secs. Still very costly but much more reasonable.

    0 讨论(0)
  • 2020-11-22 00:56
    function in_multi_array($needle, $key, $haystack) 
    {
        $in_multi_array = false;
        if (in_array($needle, $haystack))
        {
            $in_multi_array = true; 
        }else 
        {
           foreach( $haystack as $key1 => $val )
           {
               if(is_array($val)) 
               {
                   if($this->in_multi_array($needle, $key, $val)) 
                   {
                       $in_multi_array = true;
                       break;
                   }
               }
            }
        }
    
        return $in_multi_array;
    } 
    
    0 讨论(0)
提交回复
热议问题