phparraysmultidimensional-arrayfilter

Filter a 2d array to only keep rows with a specified value in a specified column


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 array:

$arr = [
    ['id' => 1, 'name' => 'cat 1'],
    ['id' => 2, 'name' => 'cat 2'],
    ['id' => 3, 'name' => 'cat 1']
];

When I search for key name and value cat 1, the function should return:

[
    ['id' => 1, 'name' => 'cat 1'],
    ['id' => 3, 'name' => 'cat 1']
]

I guess the function has to be recursive to get down to the deepest level.


Solution

  • 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).