Recherche de tableaux multidimensionnels PHP (recherche de clé par valeur spécifique)

114

J'ai ce tableau multidimensionnel. J'ai besoin de le rechercher et de ne renvoyer que la clé qui correspond à la valeur du "slug". Je sais qu'il existe d'autres discussions sur la recherche de tableaux multidimensionnels, mais je ne comprends pas vraiment assez pour s'appliquer à ma situation. Merci beaucoup pour toute aide!

J'ai donc besoin d'une fonction comme:

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

Voici le tableau:

$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'    => '',
        ),
);
Ben Kouba
la source

Réponses:

157

Très simple:

function myfunction($products, $field, $value)
{
   foreach($products as $key => $product)
   {
      if ( $product[$field] === $value )
         return $key;
   }
   return false;
}
Aurelio De Rosa
la source
6
Si vous utilisez cette fonction dans une instruction conditionnelle, vous allez vouloir faire une vérification absolue par rapport au type car la clé retournée peut parfois avoir un index de [0]. Donc, si vous faites une vérification conditionnelle, cela devrait ressembler à quelque chose comme ceci: if (myfunction($array, 'field', 'value') !== FALSE )) // do something...
Andy Cook
159

Une autre solution possible est basée sur la array_search()fonction. Vous devez utiliser PHP 5.5.0 ou supérieur.

Exemple

$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

Explication

La fonction array_search()a deux arguments. Le premier est la valeur que vous souhaitez rechercher. Le second est l'endroit où la fonction doit rechercher. La fonction array_column()obtient les valeurs des éléments dont la clé est 'uid'.

Résumé

Vous pouvez donc l'utiliser comme:

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

ou, si vous préférez:

// 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');

L'exemple original (par xfoxawy) peut être trouvé sur le DOCS .
La array_column() page .


Mettre à jour

En raison du commentaire de Vael, j'étais curieux, j'ai donc fait un test simple pour mesurer les performances de la méthode qui utilise array_searchet la méthode proposée sur la réponse acceptée.

J'ai créé un tableau qui contenait 1000 tableaux, la structure était comme ça (toutes les données étaient randomisées):

[
      {
            "_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"
      },...
]

J'ai exécuté le test de recherche 100 fois en recherchant différentes valeurs pour le champ de nom, puis j'ai calculé le temps moyen en millisecondes . Ici vous pouvez voir un exemple.

Les résultats étaient que la méthode proposée pour cette réponse nécessitait environ 2E-7 pour trouver la valeur, tandis que la méthode de réponse acceptée nécessitait environ 8E-7.

Comme je l'ai déjà dit, les deux temps sont assez acceptables pour une application utilisant un tableau de cette taille. Si la taille augmente beaucoup, disons 1M d'éléments, alors cette petite différence sera également augmentée.

Mise à jour II

J'ai ajouté un test pour la méthode basée sur array_walk_recursivelaquelle était mentionnée certaines des réponses ici. Le résultat obtenu est le bon. Et si nous nous concentrons sur la performance, c'est un peu pire que les autres examinés sur le test . Dans le test, vous pouvez voir que c'est environ 10 fois plus lent que la méthode basée sur array_search. Encore une fois, ce n'est pas une différence très pertinente pour la plupart des applications.

Mise à jour III

Merci à @mickmackusa pour avoir repéré plusieurs limitations sur cette méthode:

  • Cette méthode échouera sur les clés associatives.
  • Cette méthode ne fonctionnera que sur les sous-tableaux indexés (à partir de 0 et avoir des clés ascendantes consécutives).
Iván Rodríguez Torres
la source
Quelqu'un connaît-il la performance de cela? Il semble que ce serait finalement plus lent et nécessiterait toujours 5,5. Je ne peux pas tester car je suis sur 5.4.
Vael Victus
Pour tous ceux qui ne comprennent pas: en php 7, les boucles for sont plus rapides. Quand je suis passé à 5.6 dans cet exemple eval.in, array_search était légèrement plus rapide.
Vael Victus
intelligent! Je faisais quelque chose de similaire, en utilisant array_combine () avec array_column () pour créer un autre tableau à partir duquel récupérer ma donnée avec une clé connue, mais c'est plus élégant.
David
4
L'utilisation de array_search()avec array_column()ne fonctionnera pas sur l'exemple de tableau de l'OP car les clés de sous-tableau commencent à partir de 1. Cette méthode échouera également sur les clés associatives. Cette méthode ne fonctionnera que sur des sous-tableaux indexés (à partir de 0et avoir des clés ascendantes consécutives). La raison en est que array_column()générera de nouveaux index dans son tableau renvoyé.
mickmackusa le
tout à fait raison @mickmackusa, j'ai ajouté vos connaissances à la réponse. Merci pour l'aide
Iván Rodríguez Torres
14

Cette méthode de classe peut rechercher dans un tableau selon plusieurs 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);

Produira:

array(2) {
  [5]=>
  array(2) {
    ["foo"]=>
    string(5) "test4"
    ["bar"]=>
    string(4) "baz1"
  }
  [10]=>
  array(2) {
    ["foo"]=>
    string(5) "test4"
    ["bar"]=>
    string(4) "baz1"
  }
}
Fataliste
la source
Salut Fatalist stackoverflow.com/questions/40860030/… . Il est renvoyé à ces questions, pouvez-vous s'il vous plaît clarifier cette question
KARTHI SRV
4

Utilisez cette fonction:

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

et appelez la fonction.

print_r(searchThroughArray('breville-one-touch-tea-maker-BTM800XL',$products));
Josef
la source
Bonne réponse. Vous pouvez vérifier la performance de votre proposition sur ma réponse
Iván Rodríguez Torres
Les réponses de code uniquement sont de faible valeur sur StackOverflow. Veuillez mettre à jour votre message pour expliquer le fonctionnement de votre fonction de recherche de sous-chaînes de nœuds feuilles. Cette méthode n'est pas conçue spécifiquement pour fonctionner comme le PO le demande, il est donc important de clarifier les différences. Un lien de démonstration améliorerait considérablement la compréhension du lecteur. Publiez toujours des réponses avec l'intention d'éduquer le PO et le plus grand public de SO.
mickmackusa
1
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; 
} 
Mikelee
la source
Les réponses de code uniquement sont de faible valeur sur StackOverflow. Veuillez mettre à jour votre message pour expliquer le fonctionnement de votre méthode récursive, les situations où elle est appropriée et les situations où la récursivité est inutile. Publiez toujours des réponses avec l'intention d'éduquer le PO et le plus grand public de SO.
mickmackusa
1

Pour le prochain visiteur à venir: utilisez la promenade de tableau récursif; il visite chaque "feuille" du tableau multidimensionnel. Voici pour l'inspiration:

function getMDArrayValueByKey($a, $k) {
    $r = [];
    array_walk_recursive ($a, 
                          function ($item, $key) use ($k, &$r) {if ($key == $k) $r[] = $item;}
                          );
    return $r;
}
Hans
la source
Aucun problème! juste pour vous faire gagner du temps, si vous essayez josef answer, la fonction renvoie un tableau avec un élément. La clé est la réponse souhaitée :)
Iván Rodríguez Torres
La réponse de @Ivan josef est très différente de celle-ci. Avez-vous testé cela vous-même. Je continue à regarder cette réponse et je ne pense pas que cela puisse fonctionner car array_walk_recursive ne peut pas voir un niveau supérieur. Pour chaque clé de premier niveau, josef appelle des strpos ou vérifie tous les nœuds feuilles. Regarde la différence?
mickmackusa le
Bien sûr @mickmackusa Mais Hans donne une sorte d'inspiration, la réponse n'est pas de donner la solution littéralement. Il a besoin de plus de détails, comme Josef l'a fait sur sa réponse. Mais vous avez raison sur le fait que cette réponse ne résout pas complètement le problème.
Iván Rodríguez Torres
1

Je voudrais faire comme ci-dessous, où $productsest le tableau réel donné dans le problème au tout début.

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

Essaye ça

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;
    }
pawan sen
la source
Les réponses de code uniquement sont de faible valeur sur StackOverflow. Veuillez mettre à jour votre message pour expliquer le fonctionnement de votre méthode récursive, les situations où elle est appropriée et les situations où la récursivité est inutile. Publiez toujours des réponses avec l'intention d'éduquer le PO et le plus grand public de SO. Ps Je pense que la plupart des développeurs PHP préféreront &&et ||au lieu de ANDet ORdans votre condition. Il n'y a aucune raison de déclarer current_key. La comparaison $needledoit être stricte.
mickmackusa