PHP Multidimensional Array Searching (Find key by specific value)

PhpSearchMultidimensional ArrayKey

Php Problem Overview


I have this multidimensional array. I need to search it and return only the key that matches the value of the "slug". I know there are other threads about searching multidimensional arrays, but I'm not really understanding enough to apply to my situation. Thanks very much for any help!

So I need a function like:

myfunction($products,'breville-one-touch-tea-maker-BTM800XL');
// returns 1

Here's the Array:

$products = array (
1  => array(
		'name' 			=> 'The Breville One-Touch Tea Maker',
		'slug'			=> 'breville-one-touch-tea-maker-BTM800XL',
		'shortname'		=> 'The One-Touch Tea Maker',
		'listprice' 	=> '299.99',
		'price' 		=> '249.99',
		'rating' 		=> '9.5',
		'reviews' 		=> '81',
		'buyurl' 		=> 'http://www.amazon.com/The-Breville-One-Touch-Tea-Maker/dp/B003LNOPSG',
		'videoref1' 	=> 'xNb-FOTJY1c',
		'videoref2'		=> 'WAyk-O2B6F8',
		'image' 		=> '812BpgHhjBML.jpg',
		'related1' 		=> '2',
		'related2' 		=> '3',
		'related3' 		=> '4',
		'bestbuy'		=> '1',
		'quote'			=> '',
		'quoteautor'	=> 'K. Martino',
		),
		
2  => array(
		'name' 			=> 'Breville Variable-Temperature Kettle BKE820XL',
		'slug'			=> 'breville-variable-temperature-kettle-BKE820XL',
		'shortname'		=> 'Variable Temperature Kettle',
		'listprice' 	=> '199.99',
		'price' 		=> '129.99',
		'rating' 		=> '9',
		'reviews' 		=> '78',
		'buyurl' 		=> 'http://www.amazon.com/Breville-BKE820XL-Variable-Temperature-1-8-Liter-Kettle/dp/B001DYERBK',
		'videoref1' 	=> 'oyZWBD83xeE',
		'image' 		=> '41y2B8jSKmwL.jpg',
		'related1' 		=> '3',
		'related2' 		=> '4',
		'related3' 		=> '5',
		'bestbuy'		=> '1',
		'quote'			=> '',
		'quoteautor'	=> '',
		),
);

Php Solutions


Solution 1 - Php

Another poossible solution is based on the array_search() function. You need to use PHP 5.5.0 or higher.

Example

$userdb=Array ( (0) => Array ( (uid) => '100', (name) => 'Sandra Shush', (url) => 'urlof100' ),

(1) => Array
    (
        (uid) => '5465',
        (name) => 'Stefanie Mcmohn',
        (pic_square) => 'urlof100'
    ),

(2) => Array
    (
        (uid) => '40489',
        (name) => 'Michael',
        (pic_square) => 'urlof40489'
    )
);

$key = array_search(40489, array_column($userdb, 'uid'));

echo ("The key is: ".$key);
//This will output- The key is: 2

Explanation

The function array_search() has two arguments. The first one is the value that you want to search. The second is where the function should search. The function array_column() gets the values of the elements which key is 'uid'.

Summary

So you could use it as:

array_search('breville-one-touch-tea-maker-BTM800XL', array_column($products, 'slug'));

or, if you prefer:

// define function
function array_search_multidim($array, $column, $key){
    return (array_search($key, array_column($array, $column)));
}

// use it
array_search_multidim($products, 'slug', 'breville-one-touch-tea-maker-BTM800XL');

The original example(by xfoxawy) can be found on the DOCS.
The array_column() page.


Update

Due to Vael comment I was curious, so I made a simple test to meassure the performance of the method that uses array_search and the method proposed on the accepted answer.

I created an array which contained 1000 arrays, the structure was like this (all data was randomized):

[
      {
            "_id": "57fe684fb22a07039b3f196c",
            "index": 0,
            "guid": "98dd3515-3f1e-4b89-8bb9-103b0d67e613",
            "isActive": true,
            "balance": "$2,372.04",
            "picture": "http://placehold.it/32x32",
            "age": 21,
            "eyeColor": "blue",
            "name": "Green",
            "company": "MIXERS"
      },...
]

I ran the search test 100 times searching for different values for the name field, and then I calculated the mean time in milliseconds. Here you can see an example.

Results were that the method proposed on this answer needed about 2E-7 to find the value, while the accepted answer method needed about 8E-7.

Like I said before both times are pretty aceptable for an application using an array with this size. If the size grows a lot, let's say 1M elements, then this little difference will be increased too.

Update II

I've added a test for the method based in array_walk_recursive which was mentionend on some of the answers here. The result got is the correct one. And if we focus on the performance, its a bit worse than the others examined on the test. In the test, you can see that is about 10 times slower than the method based on array_search. Again, this isn't a very relevant difference for the most of the applications.

Update III

Thanks to @mickmackusa for spotting several limitations on this method:

  • This method will fail on associative keys.

  • This method will only work on indexed subarrays (starting from 0 and have consecutively ascending keys).

Solution 2 - Php

Very simple:

function myfunction($products, $field, $value)
{
   foreach($products as $key => $product)
   {
      if ( $product[$field] === $value )
         return $key;
   }
   return false;
}

Solution 3 - Php

This class method can search in array by multiple conditions:

class Stdlib_Array
{
    public static function multiSearch(array $array, array $pairs)
    {
        $found = array();
        foreach ($array as $aKey => $aVal) {
            $coincidences = 0;
            foreach ($pairs as $pKey => $pVal) {
                if (array_key_exists($pKey, $aVal) && $aVal[$pKey] == $pVal) {
                    $coincidences++;
                }
            }
            if ($coincidences == count($pairs)) {
                $found[$aKey] = $aVal;
            }
        }

        return $found;
    }    
}

// Example:

$data = array(
    array('foo' => 'test4', 'bar' => 'baz'),
    array('foo' => 'test',  'bar' => 'baz'),
    array('foo' => 'test1', 'bar' => 'baz3'),
    array('foo' => 'test',  'bar' => 'baz'),
    array('foo' => 'test',  'bar' => 'baz4'),
    array('foo' => 'test4', 'bar' => 'baz1'),
    array('foo' => 'test',  'bar' => 'baz1'),
    array('foo' => 'test3', 'bar' => 'baz2'),
    array('foo' => 'test',  'bar' => 'baz'),
    array('foo' => 'test',  'bar' => 'baz'),
    array('foo' => 'test4', 'bar' => 'baz1')
);

$result = Stdlib_Array::multiSearch($data, array('foo' => 'test4', 'bar' => 'baz1'));

var_dump($result);

Will produce:

array(2) {
  [5]=>
  array(2) {
    ["foo"]=>
    string(5) "test4"
    ["bar"]=>
    string(4) "baz1"
  }
  [10]=>
  array(2) {
    ["foo"]=>
    string(5) "test4"
    ["bar"]=>
    string(4) "baz1"
  }
}

Solution 4 - Php

Use this function:

function searchThroughArray($search,array $lists){
        try{
            foreach ($lists as $key => $value) {
                if(is_array($value)){
                    array_walk_recursive($value, function($v, $k) use($search ,$key,$value,&$val){
                        if(strpos($v, $search) !== false )  $val[$key]=$value;
                    });
            }else{
                    if(strpos($value, $search) !== false )  $val[$key]=$value;
                }
    
            }
            return $val;
    
        }catch (Exception $e) {
            return false;
        }
    }

and call function.

print_r(searchThroughArray('breville-one-touch-tea-maker-BTM800XL',$products));

Solution 5 - Php

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; 
} 

Solution 6 - Php

I would do like below, where $products is the actual array given in the problem at the very beginning.

print_r(
  array_search("breville-variable-temperature-kettle-BKE820XL", 
  array_map(function($product){return $product["slug"];},$products))
);

Solution 7 - Php

Try this

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

Solution 8 - Php

For the next visitor coming along: use the recursive array walk; it visits every "leaf" in the multidimensional array. Here's for inspiration:

function getMDArrayValueByKey($a, $k) {
	$r = [];
	array_walk_recursive ($a, 
	                      function ($item, $key) use ($k, &$r) {if ($key == $k) $r[] = $item;}
	                      );
	return $r;
}

Solution 9 - Php

You can convert the array to JSON and search as a string then return the found object, so no matter how deeply nested it'll find it quickly:

function findObjectByKeyValue($array, $key, $value){
    $object = [];
    $string = json_encode($array);
    $foundPosition = strpos($string, '"' . $key . '":"' . $value . '"');

    if( $foundPosition ){
        $prevBracketPos = strrpos(substr($string, 0, $foundPosition), '{');

        if( $prevBracketPos ){
            $nextBracketPos = strpos($string, '}', $foundPosition);

            if( $nextBracketPos ){
                $brackets = 0;

                while( strpos(substr($string, $foundPosition, $nextBracketPos - $foundPosition), '{') &&
                        substr_count(substr($string, $foundPosition, $nextBracketPos - $foundPosition), '{') > $brackets
                    ){
                    $lenToAdd = strlen(substr($string, $foundPosition, $nextBracketPos - $foundPosition + 1));
                    $nextBracketPos = strpos($string, '}', $foundPosition + $lenToAdd);
                    $brackets++;
                }

                $substr = substr($string, $prevBracketPos, $nextBracketPos - $prevBracketPos + 1);

                // Confirm it's wrapped with brackets before we decode
                if( substr($substr, 0, 1) === '{' && substr($substr, -1, 1) === '}' ){
                    $object = json_decode($substr, true);
                }
            }
        }
    }

    return $object;
}

Example:

$arr = [{
    "items":
    {
        "1": [
        {
            "id": "621eaf06062cd",
            "nestedItem":
            {
                "id": "123",
                "nestedItem":
                {
                    "id": "456",
                    "nestedItem":
                    {
                        "id": "789"
                    }
                }
            }
        }],
        "2": [
        {
            "id": "621eb58de7364",
        }],
        "3": [
        {
            "id": "62226910716af",
        }]
    }
}];
echo findObjectByKeyValue($arr, 'id', '123');
/* {
    "id": "123",
    "nestedItem":
    {
        "id": "456",
        "nestedItem":
        {
            "id": "789"
        }
    }
} /*
echo findObjectByKeyValue($arr, 'id', '621eaf06062cd');
/* {
    "id": "621eaf06062cd",
    "nestedItem":
    {
        "id": "123",
        "nestedItem":
        {
            "id": "456",
            "nestedItem":
            {
                "id": "789"
            }
        }
    }
} */

The only problem уоu could run into is if there're brackets within as strings in the array.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBen KoubaView Question on Stackoverflow
Solution 1 - PhpIván Rodríguez TorresView Answer on Stackoverflow
Solution 2 - PhpAurelio De RosaView Answer on Stackoverflow
Solution 3 - PhpFatalistView Answer on Stackoverflow
Solution 4 - PhpjosefView Answer on Stackoverflow
Solution 5 - PhpmikeleeView Answer on Stackoverflow
Solution 6 - PhpSam KazView Answer on Stackoverflow
Solution 7 - Phppawan senView Answer on Stackoverflow
Solution 8 - PhpHansView Answer on Stackoverflow
Solution 9 - PhpMaxView Answer on Stackoverflow