wake-up-neo.com

Wie suche ich nach Schlüssel => Wert in einem mehrdimensionalen Array in PHP

Gibt es eine schnelle Möglichkeit, alle Unterarrays abzurufen, in denen ein Schlüsselwertpaar in einem mehrdimensionalen Array gefunden wurde? Ich kann nicht sagen, wie tief das Array sein wird.

Einfaches Beispiel-Array:

$arr = array(0 => array(id=>1,name=>"cat 1"),
             1 => array(id=>2,name=>"cat 2"),
             2 => array(id=>3,name=>"cat 1")
);

Wenn ich nach key = name und value = "cat 1" suche, sollte die Funktion Folgendes zurückgeben:

array(0 => array(id=>1,name=>"cat 1"),
      1 => array(id=>3,name=>"cat 1")
);

Ich denke, die Funktion muss rekursiv sein, um auf die tiefste Ebene zu gelangen.

142
dan

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

Ausgabe:

Array
(
    [0] => Array
        (
            [id] => 1
            [name] => cat 1
        )

    [1] => Array
        (
            [id] => 3
            [name] => cat 1
        )

)

Wenn Effizienz wichtig ist, können Sie es so schreiben, dass alle rekursiven Aufrufe ihre Ergebnisse in demselben temporären $results - Array speichern, anstatt Arrays zusammenzuführen.

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

Der Schlüssel dort ist, dass search_r Seinen vierten Parameter als Referenz und nicht als Wert nimmt; Das kaufmännische Und & ist entscheidend.

Zu Ihrer Information: Wenn Sie eine ältere Version von PHP) haben, müssen Sie den Pass-by-Referenz-Teil im Aufruf zu search_r Anstatt angeben Das heißt, die letzte Zeile wird zu search_r($subarray, $key, $value, &$results).

202
John Kugelman

Wie wäre es stattdessen mit der SPL -Version? Das erspart Ihnen das Tippen:

// I changed your input example to make it harder and
// to show it works at lower depths:

$arr = array(0 => array('id'=>1,'name'=>"cat 1"),
             1 => array(array('id'=>3,'name'=>"cat 1")),
             2 => array('id'=>2,'name'=>"cat 2")
);

//here's the code:

    $arrIt = new RecursiveIteratorIterator(new RecursiveArrayIterator($arr));

 foreach ($arrIt as $sub) {
    $subArray = $arrIt->getSubIterator();
    if ($subArray['name'] === 'cat 1') {
        $outputArray[] = iterator_to_array($subArray);
    }
}

Was großartig ist, ist, dass im Grunde derselbe Code für Sie durch ein Verzeichnis iteriert, indem Sie einen RecursiveDirectoryIterator anstelle eines RecursiveArrayIterator verwenden. SPL ist der Roxor.

Das einzige Manko an SPL ist, dass es im Web schlecht dokumentiert ist. Einige PHP Bücher gehen jedoch auf einige nützliche Details ein, insbesondere Pro PHP. und Sie können wahrscheinlich auch für weitere Informationen googeln.

69
jared
<?php
$arr = array(0 => array("id"=>1,"name"=>"cat 1"),
             1 => array("id"=>2,"name"=>"cat 2"),
             2 => array("id"=>3,"name"=>"cat 1")
);
$arr = array_filter($arr, function($ar) {
   return ($ar['name'] == 'cat 1');
   //return ($ar['name'] == 'cat 1' AND $ar['id'] == '3');// you can add multiple conditions
});

echo "<pre>";
print_r($arr);

?>

Ref: http://php.net/manual/en/function.array-filter.php

42
Prasanth Bendra

Kam zurück, um dieses Update für alle zu veröffentlichen, die einen Optimierungstipp zu diesen Antworten benötigen, insbesondere John Kugelmans großartige Antwort oben.

Seine veröffentlichte Funktion funktioniert einwandfrei, aber ich musste dieses Szenario für die Verarbeitung einer Ergebnismenge von 12.000 Zeilen optimieren. Es dauerte ewig 8 Sekunden, bis die Funktion alle Datensätze durchgegangen war, waaaaaay zu lang.

Ich brauchte nur die Funktion, um die Suche zu stoppen und zurückzukehren, wenn eine Übereinstimmung gefunden wurde. Dh, wenn wir nach einer customer_id suchen, wissen wir, dass wir nur eine in der Ergebnismenge haben, und sobald wir die customer_id in dem mehrdimensionalen Array finden, möchten wir zurückkehren.

Hier ist die geschwindigkeitsoptimierte (und stark vereinfachte) Version dieser Funktion für alle, die es brauchen. Im Gegensatz zu anderen Versionen kann nur eine Tiefe des Arrays verarbeitet werden, es wird nicht wiederverwendet und das Zusammenführen mehrerer Ergebnisse entfällt.

// search array for specific key = value
public function searchSubArray(Array $array, $key, $value) {   
    foreach ($array as $subarray){  
        if (isset($subarray[$key]) && $subarray[$key] == $value)
          return $subarray;       
    } 
}

Dies brachte die Aufgabe, die 12 000 Datensätze auf 1,5 Sekunden abzugleichen, zum Erliegen. Immer noch sehr teuer aber viel vernünftiger.

16
stefgosselin
if (isset($array[$key]) && $array[$key] == $value)

Eine kleine Verbesserung zur schnellen Version.

14
blackmogu

Seien Sie vorsichtig mit linearen Suchalgorithmen (die oben genannten sind linear) in mehrdimensionalen Arrays, da sie eine erhöhte Komplexität aufweisen, da ihre Tiefe die Anzahl der zum Durchlaufen des gesamten Arrays erforderlichen Iterationen erhöht. Z.B:

array(
    [0] => array ([0] => something, [1] => something_else))
    ...
    [100] => array ([0] => something100, [1] => something_else100))
)

mit einem geeigneten Algorithmus würde es höchstens 200 Iterationen dauern, um das zu finden, wonach Sie suchen (wenn die Nadel bei [100] [1] wäre).

Lineare Algorithmen arbeiten in diesem Fall mit O(n) (Ordnungsgesamtzahl der Elemente im gesamten Array), dies ist schlecht, eine Million Einträge (z. B. ein 1000x100x10-Array) würden durchschnittlich 500.000 Iterationen benötigen Was würde auch passieren, wenn Sie die Struktur Ihres mehrdimensionalen Arrays ändern möchten? Und PHP) würde einen rekursiven Algorithmus auslösen, wenn Ihre Tiefe mehr als 100 beträgt besser:

Verwenden Sie nach Möglichkeit immer Objekte anstelle mehrdimensionaler Arrays:

ArrayObject(
   MyObject(something, something_else))
   ...
   MyObject(something100, something_else100))
)

und wenden Sie eine benutzerdefinierte Komparatorschnittstelle und -funktion an, um sie zu sortieren und zu finden:

interface Comparable {
   public function compareTo(Comparable $o);
}

class MyObject implements Comparable {
   public function compareTo(Comparable $o){
      ...
   }
}

function myComp(Comparable $a, Comparable $b){
    return $a->compareTo($b);
}

Sie können uasort() verwenden, um einen benutzerdefinierten Komparator zu verwenden. Wenn Sie sich abenteuerlustig fühlen, sollten Sie Ihre eigenen Sammlungen für Ihre Objekte implementieren, die sie sortieren und verwalten können (ich erweitere ArrayObject immer um eine Suchfunktion ganz oben am wenigsten).

$arrayObj->uasort("myComp");

Sobald sie sortiert sind (uasort ist O (n log n), was so gut ist, wie es über beliebige Daten geht), kann die binäre Suche die Operation in O (log n) -Zeit ausführen, dh eine Million Einträge benötigt nur ~ 20 Iterationen bis Suche. Soweit mir bekannt ist, dass die benutzerdefinierte Komparator-Binärsuche nicht in PHP (array_search() verwendet eine natürliche Reihenfolge, die auf Objektreferenzen und nicht auf deren Eigenschaften angewendet wird) implementiert ist, müssten Sie diese implementieren Das bist du selbst wie ich.

Dieser Ansatz ist effizienter (es gibt keine Tiefe mehr) und vor allem universeller (vorausgesetzt, Sie erzwingen die Vergleichbarkeit mithilfe von Schnittstellen), da Objekte definieren, wie sie sortiert sind, sodass Sie den Code unendlich oft wiederverwenden können. Viel besser =)

7
mbdxgdb2
$result = array_filter($arr, function ($var) {   
  $found = false;
  array_walk_recursive($var, function ($item, $key) use (&$found) {  
    $found = $found || $key == "name" && $item == "cat 1";
  });
  return $found;
});
5

Hier ist Lösung:

<?php
$students['e1003']['birthplace'] = ("Mandaluyong <br>");
$students['ter1003']['birthplace'] = ("San Juan <br>");
$students['fgg1003']['birthplace'] = ("Quezon City <br>");
$students['bdf1003']['birthplace'] = ("Manila <br>");

$key = array_search('Delata Jona', array_column($students, 'name'));
echo $key;  

?>
4
Tristan
function in_multi_array($needle, $key, $haystack) 
{
    $in_multi_array = false;
    if (in_array($needle, $haystack))
    {
        $in_multi_array = true; 
    }else 
    {
       foreach( $haystack as $key1 => $val )
       {
           if(is_array($val)) 
           {
               if($this->in_multi_array($needle, $key, $val)) 
               {
                   $in_multi_array = true;
                   break;
               }
           }
        }
    }

    return $in_multi_array;
} 
3
radhe

http://snipplr.com/view/51108/nested-array-search-by-value-or-key/

<?php

//PHP 5.3

function searchNestedArray(array $array, $search, $mode = 'value') {

    foreach (new RecursiveIteratorIterator(new RecursiveArrayIterator($array)) as $key => $value) {
        if ($search === ${${"mode"}})
            return true;
    }
    return false;
}

$data = array(
    array('abc', 'ddd'),
    'ccc',
    'bbb',
    array('aaa', array('yyy', 'mp' => 555))
);

var_dump(searchNestedArray($data, 555));
3
Pramendra Gupta

Dies ist eine überarbeitete Funktion von der, die John K. gepostet hat ... Ich muss nur den spezifischen Schlüssel im Array und nichts darüber greifen.

function search_array ( $array, $key, $value )
{
    $results = array();

    if ( is_array($array) )
    {
        if ( $array[$key] == $value )
        {
            $results[] = $array;
        } else {
            foreach ($array as $subarray) 
                $results = array_merge( $results, $this->search_array($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_array($arr, 'name', 'cat 1'));
2
Trevor Lettman

Ich brauchte etwas Ähnliches, aber um ein mehrdimensionales Array nach Wert zu suchen ... Ich nahm John als Beispiel und schrieb

function _search_array_by_value($array, $value) {
        $results = array();
        if (is_array($array)) {
            $found = array_search($value,$array);
            if ($found) {
                $results[] = $found;
            }
            foreach ($array as $subarray)
                $results = array_merge($results, $this->_search_array_by_value($subarray, $value));
        }
        return $results;
    }

Ich hoffe es hilft jemandem :)

2
confiq

Und eine andere Version, die den Schlüsselwert aus dem Array-Element zurückgibt, in dem sich der Wert befindet (keine Rekursion, optimiert für Geschwindigkeit):

// if the array is 
$arr['apples'] = array('id' => 1);
$arr['oranges'] = array('id' => 2);

//then 
print_r(search_array($arr, 'id', 2);
// returns Array ( [oranges] => Array ( [id] => 2 ) ) 
// instead of Array ( [0] => Array ( [id] => 2 ) )

// search array for specific key = value
function search_array($array, $key, $value) {
  $return = array();   
  foreach ($array as $k=>$subarray){  
    if (isset($subarray[$key]) && $subarray[$key] == $value) {
      $return[$k] = $subarray;
      return $return;
    } 
  }
}

Vielen Dank an alle, die hier gepostet haben.

1
Darko Hrgovic
function findKey($tab, $key){
    foreach($tab as $k => $value){ 
        if($k==$key) return $value; 
        if(is_array($value)){ 
            $find = findKey($value, $key);
            if($find) return $find;
        }
    }
    return null;
}
1
Monaem AMINA