PHP Multidimensional Array Searching (Schlüssel anhand eines bestimmten Werts suchen)

114

Ich habe dieses mehrdimensionale Array. Ich muss es suchen und nur den Schlüssel zurückgeben, der dem Wert des "Slugs" entspricht. Ich weiß, dass es andere Themen zum Durchsuchen mehrdimensionaler Arrays gibt, aber ich verstehe nicht genug, um sie auf meine Situation anzuwenden. Vielen Dank für jede Hilfe!

Ich brauche also eine Funktion wie:

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

Hier ist das 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'    => '',
        ),
);
Ben Kouba
quelle

Antworten:

157

Sehr einfach:

function myfunction($products, $field, $value)
{
   foreach($products as $key => $product)
   {
      if ( $product[$field] === $value )
         return $key;
   }
   return false;
}
Aurelio De Rosa
quelle
6
Wenn Sie diese Funktion in einer bedingten Anweisung verwenden, möchten Sie eine absolute Überprüfung des Typs durchführen, da der zurückgegebene Schlüssel manchmal den Index [0] haben kann. Wenn Sie also eine bedingte Überprüfung durchführen, sollte dies ungefähr so ​​aussehen: if (myfunction($array, 'field', 'value') !== FALSE )) // do something...
Andy Cook,
159

Eine andere mögliche Lösung basiert auf der array_search()Funktion. Sie müssen PHP 5.5.0 oder höher verwenden.

Beispiel

$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

Erläuterung

Die Funktion array_search()hat zwei Argumente. Der erste ist der Wert, den Sie suchen möchten. Die zweite ist, wo die Funktion suchen sollte. Die Funktion array_column()ruft die Werte der Elemente ab, um welche Taste es sich handelt 'uid'.

Zusammenfassung

Sie können es also verwenden als:

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

oder, wenn Sie es vorziehen:

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

Das Originalbeispiel (von xfoxawy) finden Sie im DOCS .
Die array_column() Seite .


Aktualisieren

Aufgrund des Kommentars von Vael war ich neugierig und machte einen einfachen Test, um die Leistung der verwendeten Methode array_searchund die für die akzeptierte Antwort vorgeschlagene Methode zu messen .

Ich habe ein Array erstellt, das 1000 Arrays enthielt. Die Struktur war wie folgt (alle Daten wurden zufällig ausgewählt):

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

Ich habe den Suchtest 100 Mal durchgeführt, um nach verschiedenen Werten für das Namensfeld zu suchen, und dann die mittlere Zeit in Millisekunden berechnet . Hier sehen Sie ein Beispiel.

Die Ergebnisse waren, dass die für diese Antwort vorgeschlagene Methode etwa 2E-7 benötigte, um den Wert zu finden, während die akzeptierte Antwortmethode etwa 8E-7 benötigte.

Wie ich bereits sagte, sind beide Zeiten für eine Anwendung mit einem Array dieser Größe ziemlich akzeptabel. Wenn die Größe stark wächst, sagen wir 1M Elemente, dann wird auch dieser kleine Unterschied größer.

Update II

Ich habe einen Test für die Methode hinzugefügt, der array_walk_recursiveauf einigen der Antworten hier erwähnt wurde. Das Ergebnis ist das richtige. Und wenn wir uns auf die Leistung konzentrieren, ist sie etwas schlechter als die anderen, die im Test untersucht wurden . Im Test können Sie feststellen, dass dies etwa zehnmal langsamer ist als die darauf basierende Methode array_search. Auch dies ist für die meisten Anwendungen kein sehr relevanter Unterschied.

Update III

Vielen Dank an @mickmackusa für das Erkennen einiger Einschränkungen dieser Methode:

  • Diese Methode schlägt bei assoziativen Schlüsseln fehl.
  • Diese Methode funktioniert nur bei indizierten Subarrays (beginnend mit 0 und mit nacheinander aufsteigenden Schlüsseln).
Iván Rodríguez Torres
quelle
Kennt jemand die Leistung davon? Es scheint, als wäre es letztendlich langsamer und würde immer noch 5.5 erfordern. Ich kann nicht testen, da ich auf 5.4 bin.
Vael Victus
Für alle, die nicht verstehen: In PHP 7 sind die for-Schleifen schneller. Als ich in diesem Beispiel auf 5.6 umgestellt habe, war array_search etwas schneller.
Vael Victus
klug! Ich habe etwas Ähnliches gemacht und array_combine () mit array_column () verwendet, um ein anderes Array zu erstellen, aus dem ich mein Datum mit einem bekannten Schlüssel abrufen kann, aber das ist eleganter.
David
4
Die Verwendung array_search()mit array_column()funktioniert nicht im Beispielarray des OP, da die Subarray-Schlüssel von beginnen 1. Diese Methode schlägt auch bei assoziativen Schlüsseln fehl. Diese Methode funktioniert nur bei indizierten Subarrays (ausgehend von 0und mit nacheinander aufsteigenden Schlüsseln). Der Grund dafür ist, dass array_column()in seinem zurückgegebenen Array neue Indizes generiert werden.
Mickmackusa
völlig richtig @mickmackusa, ich habe Ihr Wissen zur Antwort hinzugefügt. Vielen Dank für die Hilfe
Iván Rodríguez Torres
14

Diese Klassenmethode kann im Array nach mehreren Bedingungen suchen:

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

Wird herstellen:

array(2) {
  [5]=>
  array(2) {
    ["foo"]=>
    string(5) "test4"
    ["bar"]=>
    string(4) "baz1"
  }
  [10]=>
  array(2) {
    ["foo"]=>
    string(5) "test4"
    ["bar"]=>
    string(4) "baz1"
  }
}
Fatalist
quelle
Hallo Fatalist stackoverflow.com/questions/40860030/… . Es wird auf diese Frage zurückgeführt. Können Sie diese Frage bitte klären
?
4

Verwenden Sie diese Funktion:

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

und Funktion aufrufen.

print_r(searchThroughArray('breville-one-touch-tea-maker-BTM800XL',$products));
Josef
quelle
Gute Antwort. Sie können die Leistung Ihres Vorschlags auf meiner Antwort überprüfen
Iván Rodríguez Torres
Nur-Code-Antworten sind bei StackOverflow von geringem Wert. Bitte aktualisieren Sie Ihren Beitrag, um zu erklären, wie Ihre Suchfunktion für Blattknoten-Teilzeichenfolgen funktioniert. Diese Methode ist nicht speziell für die Arbeit des OP konzipiert, daher ist es wichtig, die Unterschiede zu klären. Ein Demo-Link würde das Leserverständnis erheblich verbessern. Veröffentlichen Sie Antworten immer mit der Absicht, das OP und das größere SO-Publikum zu informieren.
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
quelle
Nur-Code-Antworten sind bei StackOverflow von geringem Wert. Bitte aktualisieren Sie Ihren Beitrag, um zu erklären, wie Ihre rekursive Methode funktioniert, in welchen Situationen sie angemessen ist und in welchen Situationen eine Rekursion nicht erforderlich ist. Veröffentlichen Sie Antworten immer mit der Absicht, das OP und das größere SO-Publikum zu informieren.
Mickmackusa
1

Für den nächsten Besucher: Verwenden Sie den rekursiven Array-Spaziergang. es besucht jedes "Blatt" im mehrdimensionalen Array. Hier ist zur Inspiration:

function getMDArrayValueByKey($a, $k) {
    $r = [];
    array_walk_recursive ($a, 
                          function ($item, $key) use ($k, &$r) {if ($key == $k) $r[] = $item;}
                          );
    return $r;
}
Hans
quelle
Kein Problem! Nur um Ihnen Zeit zu sparen, gibt die Funktion ein Array mit einem Element zurück, wenn Sie Josef Answer versuchen. Der Schlüssel ist die gewünschte Antwort :)
Iván Rodríguez Torres
@ Ivan Josefs Antwort unterscheidet sich sehr von dieser. Hast du das selbst getestet? Ich beäugte diese Antwort immer wieder und glaube nicht, dass sie funktionieren kann, weil array_walk_recursive kein Level höher sehen kann. Für jeden Schlüssel der ersten Ebene ruft Josef Strpos auf oder überprüft alle Blattknoten. Sieh den Unterschied?
Mickmackusa
Natürlich @mickmackusa Aber Hans gibt eine Art Inspiration, die Antwort ist nicht, die Lösung wörtlich zu geben. Es bedarf weiterer Ausarbeitung, wie es Josef bei seiner Antwort getan hat. Sie haben jedoch Recht, dass diese Antwort das Problem nicht vollständig angeht.
Iván Rodríguez Torres
1

Ich möchte unten, wo $productsist das tatsächliche Array in dem Problem am Anfang angegeben.

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

Versuche dies

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
quelle
Nur-Code-Antworten sind bei StackOverflow von geringem Wert. Bitte aktualisieren Sie Ihren Beitrag, um zu erklären, wie Ihre rekursive Methode funktioniert, in welchen Situationen sie angemessen ist und in welchen Situationen eine Rekursion nicht erforderlich ist. Veröffentlichen Sie Antworten immer mit der Absicht, das OP und das größere SO-Publikum zu informieren. Ps Ich denke, die meisten PHP-Entwickler werden es vorziehen &&und ||anstelle von ANDund ORin Ihrem Zustand. Es gibt keinen Grund zu erklären current_key. Der Vergleich $needlesollte streng sein.
Mickmackusa