PHP Multidimensional Array Searching (Trova chiave per valore specifico)


114

Ho questo array multidimensionale. Devo cercarlo e restituire solo la chiave che corrisponde al valore di "slug". So che ci sono altre discussioni sulla ricerca di array multidimensionali, ma non capisco abbastanza per applicarlo alla mia situazione. Grazie mille per qualsiasi aiuto!

Quindi ho bisogno di una funzione come:

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

Ecco l'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'    => '',
        ),
);

Risposte:


157

Molto semplice:

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

6
Se stai usando questa funzione in un'istruzione condizionale, vorrai fare un controllo assoluto rispetto al tipo perché la chiave restituita a volte può avere un indice di [0]. Quindi, se si esegue un controllo condizionale, dovrebbe assomigliare a questo: if (myfunction($array, 'field', 'value') !== FALSE )) // do something...
Andy Cook

159

Un'altra soluzione possibile si basa sulla array_search()funzione. Devi usare PHP 5.5.0 o superiore.

Esempio

$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

Spiegazione

La funzione array_search()ha due argomenti. Il primo è il valore che vuoi cercare. Il secondo è dove la funzione dovrebbe cercare. La funzione array_column()ottiene i valori degli elementi quale chiave è 'uid' .

Sommario

Quindi potresti usarlo come:

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

oppure, se preferisci:

// 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'esempio originale (di xfoxawy) può essere trovato su DOCS .
La array_column() pagina .


Aggiornare

A causa del commento di Vael ero curioso, quindi ho fatto un semplice test per misurare le prestazioni del metodo che utilizza array_searche il metodo proposto sulla risposta accettata.

Ho creato un array che conteneva 1000 array, la struttura era così (tutti i dati erano randomizzati):

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

Ho eseguito il test di ricerca 100 volte cercando valori diversi per il campo del nome, quindi ho calcolato il tempo medio in millisecondi . Qui puoi vedere un esempio.

I risultati sono stati che il metodo proposto su questa risposta richiedeva circa 2E-7 per trovare il valore, mentre il metodo di risposta accettato richiedeva circa 8E-7.

Come ho detto prima, entrambe le volte sono abbastanza accettabili per un'applicazione che utilizza un array di queste dimensioni. Se la dimensione cresce molto, diciamo 1 milione di elementi, anche questa piccola differenza aumenterà.

Aggiorna II

Ho aggiunto un test per il metodo basato su array_walk_recursivecui è stato menzionato alcune delle risposte qui. Il risultato ottenuto è quello corretto. E se ci concentriamo sulle prestazioni, è un po 'peggiore rispetto agli altri esaminati nel test . Nel test, puoi vedere che è circa 10 volte più lento del metodo basato su array_search. Ancora una volta, questa non è una differenza molto rilevante per la maggior parte delle applicazioni.

Aggiorna III

Grazie a @mickmackusa per aver individuato diverse limitazioni su questo metodo:

  • Questo metodo fallirà sulle chiavi associative.
  • Questo metodo funzionerà solo sui sottoarray indicizzati (a partire da 0 e con chiavi consecutivamente crescenti).

Qualcuno conosce le prestazioni di questo? Sembra che alla fine sarebbe più lento e richiederebbe comunque 5.5. Non riesco a testare perché sono in 5.4.
Vael Victus

Per chi non capisce: in php 7, i cicli for sono più veloci. Quando sono passato a 5.6 in quell'esempio eval.in, array_search era leggermente più veloce.
Vael Victus

intelligente! Stavo facendo qualcosa di simile, usando array_combine () con array_column () per creare un altro array da cui prendere il mio dato con una chiave nota, ma questo è più elegante.
David

4
L'utilizzo array_search()con array_column()non funzionerà sull'array di esempio dell'OP perché le chiavi del sottoarray iniziano da 1. Questo metodo fallirà anche sulle chiavi associative. Questo metodo funziona solo su sottoarray indicizzati (a partire da 0e hanno chiavi consecutivamente crescenti). Il motivo è perché array_column()genererà nuovi indici nella matrice restituita.
mickmackusa

totalmente corretto @mickmackusa, ho aggiunto le tue conoscenze alla risposta. Grazie per l'aiuto
Iván Rodríguez Torres

14

Questo metodo di classe può cercare nell'array in base a più condizioni:

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

Produrrà:

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

Ciao Fatalist stackoverflow.com/questions/40860030/… . È collegato a queste domande, puoi chiarire questa domanda
KARTHI SRV

4

Usa questa funzione:

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

e chiamata funzione.

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

Bella risposta. Puoi controllare l'andamento della tua proposta sulla mia risposta
Iván Rodríguez Torres

Le risposte di solo codice hanno un valore basso su StackOverflow. Aggiorna il tuo post per spiegare come funziona la funzione di ricerca della sottostringa del nodo foglia. Questo metodo non è progettato specificamente per funzionare come richiesto dal PO, quindi è importante chiarire le differenze. Un link demo migliorerebbe notevolmente la comprensione del lettore. Pubblica sempre le risposte con l'intento di educare l'OP e il pubblico più ampio di 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; 
} 

Le risposte di solo codice hanno un valore basso su StackOverflow. Aggiorna il tuo post per spiegare come funziona il tuo metodo ricorsivo, le situazioni in cui è appropriato e le situazioni in cui la ricorsione non è necessaria. Pubblica sempre le risposte con l'intento di educare l'OP e il pubblico più ampio di SO.
mickmackusa

1

Per il prossimo visitatore che arriva: usa l'array ricorsivo walk; visita ogni "foglia" nell'array multidimensionale. Ecco per l'ispirazione:

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

Nessun problema! solo per risparmiare tempo, se provi a rispondere a josef, la funzione restituisce un array con un elemento. La chiave è la risposta desiderata :)
Iván Rodríguez Torres

La risposta di @Ivan josef è molto diversa da questa. L'hai testato tu stesso. Continuo a guardare questa risposta e non penso che possa funzionare perché array_walk_recursive non può vedere un livello superiore. Per ogni chiave di primo livello, josef chiama strpos o controlla tutti i leafnodes. Vedi la differenza?
mickmackusa

Ovviamente @mickmackusa Ma Hans sta dando una sorta di ispirazione, la risposta non è dare la soluzione letteralmente. Necessita di ulteriori elaborazioni, come ha fatto Josef nella sua risposta. Ma hai ragione nel punto che questa risposta non affronta completamente il problema.
Iván Rodríguez Torres

1

Vorrei fare come di seguito, dove si $productstrova l'array effettivo fornito nel problema all'inizio.

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

0

Prova questo

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

Le risposte di solo codice hanno un valore basso su StackOverflow. Aggiorna il tuo post per spiegare come funziona il tuo metodo ricorsivo, le situazioni in cui è appropriato e le situazioni in cui la ricorsione non è necessaria. Pubblica sempre le risposte con l'intento di educare l'OP e il pubblico più ampio di SO. Ps Penso che la maggior parte degli sviluppatori php preferirà &&e ||invece di ANDe ORnelle tue condizioni. Non c'è motivo di dichiarare current_key. Il confronto su $needledovrebbe essere rigoroso.
mickmackusa
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.