PHP - Eintrag nach Objekteigenschaft aus einem Array von Objekten suchen

174

Das Array sieht folgendermaßen aus:

[0] => stdClass Object
        (
            [ID] => 420
            [name] => Mary
         )

[1] => stdClass Object
        (
            [ID] => 10957
            [name] => Blah
         )
...

Und ich habe eine ganzzahlige Variable namens $v.

Wie kann ich einen Array-Eintrag auswählen, der ein Objekt enthält, für das die IDEigenschaft den $vWert hat?

Alex
quelle

Antworten:

189

Sie iterieren entweder das Array, suchen nach dem bestimmten Datensatz (in einer einmaligen Suche in Ordnung) oder erstellen eine Hashmap mit einem anderen assoziativen Array.

Für die ersteren so etwas

$item = null;
foreach($array as $struct) {
    if ($v == $struct->ID) {
        $item = $struct;
        break;
    }
}

Weitere Informationen zu letzterem finden Sie in dieser Frage und den nachfolgenden Antworten. Referenzieren Sie das PHP-Array nach mehreren Indizes

Phil
quelle
3
Das Setzen von $ item auf null ist nicht erforderlich.
dAm2K
32
Ups, da ist es :) Das ist für den Fall, dass das gesuchte Element nicht im Array ist. Alternativ könnten Sie verwenden, isset($item)aber ich bevorzuge es, Variablen richtig zu initialisieren
Phil
3
Für diejenigen von Ihnen, deren Schlüsselwerte auf Strings gesetzt sind, verwenden Sieif($v == $struct["ID"]){...
wbadart
67

YurkamTim ist richtig. Es bedarf nur einer Änderung:

Nach der Funktion ($) benötigen Sie einen Zeiger auf die externe Variable durch "use (& $ searchedValue)" und können dann auf die externe Variable zugreifen. Sie können es auch ändern.

$neededObject = array_filter(
    $arrayOfObjects,
    function ($e) use (&$searchedValue) {
        return $e->id == $searchedValue;
    }
);
Daniel Hardt
quelle
2
Sie haben Recht mit der Änderung und es ist eine nette Methode, aber ich habe die Geschwindigkeit im Vergleich zum Durchlaufen des Objekts getestet - Sie selbst, denn wie @phil betont hat, macht array_filter dies auch - und diese Methode dauert ungefähr fünf mal länger. Mein Testobjekt ist kein großes, daher könnte es noch schlimmer werden.
Nicolai
9
Dies &ist beim Import $searchedValuein den Schließungsbereich nicht erforderlich . Mit &wird eine Referenz erstellt, die nur benötigt wird, wenn $searchedValuesie innerhalb des Verschlusses geändert wurde.
Stefan Gehrig
Das ist cool. Ich wusste nicht, dass PHP solche Dinge tun kann. Ich dachte, globaldie einzige Möglichkeit wäre, Daten in Funktionen zu teilen! Aber es ist schade, wenn dies tatsächlich langsam ist. :(
NoOne
13
TS hat nach einem einzelnen Eintrag gefragt, dieser Code gibt ein Array zurück.
Pavel Vlasov
57
$arr = [
  [
    'ID' => 1
  ]
];

echo array_search(1, array_column($arr, 'ID')); // prints 0 (!== false)
Tim
quelle
3
Ich bin mir nicht sicher, warum dies nicht die bevorzugte Antwort ist. Liegt es daran, dass Sie zwei Funktionen aufrufen?
doz87
1
Ich glaube ich war zu spät für die Party;) Der Mangel und die Lesbarkeit ohne Schleifen und Pausen würden es vernünftig machen. Habe es aber noch nicht bewertet. Sie haben in PHP viele Optionen, um dasselbe zu erreichen.
Tim
3
Sehr elegante Lösung. Funktioniert auch mit einem Array von Objekten in PHP 7. Für PHP 5: array_search ($ object-> id, array_map (Funktion ($ object) {return $ object-> id;}, $ Objekte)); Für PHP 7: array_search ($ object-> id, array_column ($ Objekte, 'id'));
Mike
3
Dies ist nicht die bevorzugte Antwort, da op nach einem Array von Objekten fragt und diese Antwort nur reine Arrays behandelt.
Dwza
8
das ist nicht richtig Dieser Code behandelt Array von Objekten / nicht flachen Arrays
Tim
31

Ich habe hier eine elegantere Lösung gefunden . Angepasst an die Frage könnte es so aussehen:

$neededObject = array_filter(
    $arrayOfObjects,
    function ($e) use ($searchedValue) {
        return $e->id == $searchedValue;
    }
);
YurkaTim
quelle
16
+1, array_filtergibt jedoch ein Array zurück und stoppt nicht beim ersten gefundenen Wert.
Carlos Campderrós
4
Es wird $searchedValueinnerhalb der Funktion nicht erkannt . Aber draußen ist es.
M. Ahmad Zafar
4
Für den Anfang funktioniert dieser Code nicht so, wie er $searchedValueaußerhalb des Schließungsbereichs liegt. Zweitens, wie funktionieren diese Array-Methoden Ihrer Meinung nach? Sie alle durchlaufen das Array intern
Phil
1
In der Zeit der Multi-Cores könnte dies - in anderen Programmierumgebungen leider - parallel verarbeitet werden, die obige Schleife nicht unbedingt
FloydThreepwood
3
Um verwenden zu $searchedValuemüssen, schreiben Siefunction ($e) use ($searchedValue) {
Vilintritenmert
20

Wenn Sie array_column zum erneuten Indizieren verwenden, sparen Sie Zeit, wenn Sie mehrmals suchen müssen:

$lookup = array_column($arr, NULL, 'id');   // re-index by 'id'

Dann können Sie einfach $lookup[$id]nach Belieben.

Museful
quelle
3
Dies war die erstaunlichste Antwort, auch wenn es nicht die intuitivste ist ...
Thiago Natanael
11
class ArrayUtils
{
    public static function objArraySearch($array, $index, $value)
    {
        foreach($array as $arrayInf) {
            if($arrayInf->{$index} == $value) {
                return $arrayInf;
            }
        }
        return null;
    }
}

Es so zu verwenden, wie Sie es wollten, wäre ungefähr so:

ArrayUtils::objArraySearch($array,'ID',$v);
Pablo SG Pacheco
quelle
9

Versuchen

$entry = current(array_filter($array, function($e) use($v){ return $e->ID==$v; }));

Arbeitsbeispiel hier

Kamil Kiełczewski
quelle
1
Sehr sehr nützlich! Dank bro!
Fernando León
es wird nicht beim ersten gefundenen Element aufhören, oder?
Yaugenka
7

Wenn Sie einen kleinen Fehler im @YurkaTim beheben , funktioniert Ihre Lösung für mich, aber Sie fügen hinzu use:

Zur Nutzung $searchedValueinnerhalb der Funktion kann eine Lösung sein , use ($searchedValue)nachdem Funktionsparameter function ($e) HERE.

Die array_filterFunktion kehrt nur dann zurück, $neededObjectwenn die Bedingung für die Rückgabe lautettrue

Wenn $searchedValueist eine Zeichenfolge oder eine Ganzzahl:

$searchedValue = 123456; // Value to search.
$neededObject = array_filter(
    $arrayOfObjects,
    function ($e) use ($searchedValue) {
        return $e->id == $searchedValue;
    }
);
var_dump($neededObject); // To see the output

Wenn $searchedValueist Array, wo wir mit einer Liste überprüfen müssen:

$searchedValue = array( 1, 5 ); // Value to search.
$neededObject  = array_filter(
    $arrayOfObjects,
    function ( $e ) use ( $searchedValue ) {
        return in_array( $e->term_id, $searchedValue );
    }
);
var_dump($neededObject); // To see the output
Jose Carlos Ramos Carmenates
quelle
1
Ich denke, die letzte Zeile sollte sein var_dump($neededObject);:)
Sliq
3

Manchmal verwende ich gerne die Funktion array_reduce () , um die Suche durchzuführen. Es ähnelt array_filter (), wirkt sich jedoch nicht auf das gesuchte Array aus, sodass Sie mehrere Suchvorgänge für dasselbe Array von Objekten durchführen können.

$haystack = array($obj1, $obj2, ...); //some array of objects
$needle = 'looking for me?'; //the value of the object's property we want to find

//carry out the search
$search_results_array = array_reduce(
  $haystack,

  function($result_array, $current_item) use ($needle){
      //Found the an object that meets criteria? Add it to the the result array 
      if ($current_item->someProperty == $needle){
          $result_array[] = $current_item;
      }
      return $result_array;
  },
  array() //initially the array is empty (i.e.: item not found)
);

//report whether objects found
if (count($search_results_array) > 0){
  echo "found object(s): ";
  print_r($search_results_array[0]); //sample object found
} else {
  echo "did not find object(s): ";
}
Yuvilio
quelle
1
Sie haben einen Tippfehler in Ihrer Bedingung, in dem Sie dem Ergebnisfeld hinzufügen. Es sollte dies sein:if ($current_item->someProperty == $needle){ $result_array[] = $current_item; }
adrum
Angepasst. Danke @adrum!
Yuvilio
1

Ich habe das mit einer Art Java-Keymap gemacht. In diesem Fall müssen Sie Ihr Objektarray nicht jedes Mal durchlaufen.

<?php

//This is your array with objects
$object1 = (object) array('id'=>123,'name'=>'Henk','age'=>65);
$object2 = (object) array('id'=>273,'name'=>'Koos','age'=>25);
$object3 = (object) array('id'=>685,'name'=>'Bram','age'=>75);
$firstArray = Array($object1,$object2);
var_dump($firstArray);

//create a new array
$secondArray = Array();
//loop over all objects
foreach($firstArray as $value){
    //fill second        key          value
    $secondArray[$value->id] = $value->name;
}

var_dump($secondArray);

echo $secondArray['123'];

Ausgabe:

array (size=2)
  0 => 
    object(stdClass)[1]
      public 'id' => int 123
      public 'name' => string 'Henk' (length=4)
      public 'age' => int 65
  1 => 
    object(stdClass)[2]
      public 'id' => int 273
      public 'name' => string 'Koos' (length=4)
      public 'age' => int 25
array (size=2)
  123 => string 'Henk' (length=4)
  273 => string 'Koos' (length=4)
Henk
Mart-Jan
quelle
Ah, das Array nach ID neu indizieren! Ich mache das häufig und es macht die Dinge schöner.
Kzqai
1

Weg, um sofort den ersten Wert zu erhalten:

$neededObject = array_reduce(
    $arrayOfObjects,
    function ($result, $item) use ($searchedValue) {
        return $item->id == $searchedValue ? $item : $result;
    }
);
AndreyP
quelle
0

Ich habe hier veröffentlicht, was ich verwende, um genau dieses Problem mithilfe eines schnellen binären Suchalgorithmus effizient zu lösen: https://stackoverflow.com/a/52786742/1678210

Ich wollte nicht die gleiche Antwort kopieren. Jemand anderes hatte es etwas anders gefragt, aber die Antwort ist dieselbe.

Justin Jack
quelle