PHP: trova la voce per proprietà dell'oggetto da una matrice di oggetti


174

L'array si presenta come:

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

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

E ho una variabile intera chiamata $v.

Come posso selezionare una voce di array che ha un oggetto in cui la IDproprietà ha il $vvalore?

Risposte:


189

Puoi iterare l'array, cercare il record particolare (ok in una sola ricerca) o creare una hashmap usando un altro array associativo.

Per il primo, qualcosa del genere

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

Vedere questa domanda e le risposte successive per ulteriori informazioni su quest'ultimo: riferimento PHP array per più indici


3
non è necessario impostare $ item su null.
dAm2K,

32
Oops, eccolo :) Nel caso in cui l'elemento cercato non sia nella matrice. In alternativa, potresti usare isset($item)ma preferisco inizializzare correttamente le variabili
Phil

3
Per quelli di voi con valori chiave impostati su stringhe usareif($v == $struct["ID"]){...
wbadart

67

YurkamTim ha ragione. Ha solo bisogno di una modifica:

Dopo la funzione ($) è necessario un puntatore alla variabile esterna tramite "use (& $earchValue)" e quindi è possibile accedere alla variabile esterna. Inoltre puoi modificarlo.

$neededObject = array_filter(
    $arrayOfObjects,
    function ($e) use (&$searchedValue) {
        return $e->id == $searchedValue;
    }
);

2
Hai ragione sulla modifica ed è una specie di metodo accurato, ma ho testato la velocità rispetto all'iterazione attraverso l'oggetto - te stesso, perché come ha sottolineato @phil, array_filter sta facendo anche questo - e questo metodo richiede circa cinque tempi più lunghi. Il mio oggetto di test non è grande, quindi potrebbe peggiorare ulteriormente.
Nicolai,

9
Non &è richiesto durante l'importazione $searchedValuenell'ambito di chiusura. La &viene utilizzato per creare un riferimento che è necessaria solo se $searchedValueè stato modificato all'interno della chiusura.
Stefan Gehrig,

Questo è figo. Non sapevo che PHP potesse fare cose del genere. Pensavo che usare globalfosse l'unico modo per condividere i dati nelle funzioni! Ma è un peccato se questo è davvero lento. :(
NoOne,

13
TS ha richiesto una singola voce, questo codice restituisce un array.
Pavel Vlasov,

57
$arr = [
  [
    'ID' => 1
  ]
];

echo array_search(1, array_column($arr, 'ID')); // prints 0 (!== false)

3
Non sono sicuro del perché questa non sia la risposta preferita. È perché stai chiamando due funzioni?
doz87,

1
Penso di essere troppo tardi per la festa;) La sua carenza e leggibilità senza loop e interruzioni lo renderebbero ragionevole. Ma non l'ho ancora confrontato. Hai molte opzioni in PHP per ottenere lo stesso.
Tim

3
Soluzione molto elegante. Funziona anche con un array di oggetti in PHP 7. Per PHP 5: array_search ($ oggetto-> id, array_map (funzione ($ oggetto) {return $ oggetto-> id;}, $ oggetti)); Per PHP 7: array_search ($ object-> id, array_column ($ object, 'id'));
Mike,

3
Questa non è la risposta preferita perché op richiede array di oggetti e questo risponde solo a matrici pure.
Dwza,

8
non è corretto. questo codice gestisce array di oggetti / matrici non piatte
Tim

31

Ho trovato una soluzione più elegante qui . Adattato alla domanda potrebbe apparire come:

$neededObject = array_filter(
    $arrayOfObjects,
    function ($e) use ($searchedValue) {
        return $e->id == $searchedValue;
    }
);

16
+1 ma array_filterrestituisce un array e non si fermerà al primo valore trovato.
Carlos Campderrós,

4
Non sta riconoscendo $searchedValueall'interno della funzione. Ma fuori lo è.
M. Ahmad Zafar,

4
Per cominciare, questo codice non funziona in quanto non $searchedValuerientra nell'ambito di chiusura. In secondo luogo, come pensi che funzionino questi metodi di array? Tutti fanno un giro sull'array internamente
Phil

1
Al tempo dei multi core, questo - purtroppo in altri ambienti di programmazione - potrebbe essere elaborato in parallelo, il ciclo sopra non necessariamente
FloydThreepwood

3
Per usare $searchedValuebisogno scrivifunction ($e) use ($searchedValue) {
Vilintritenmert il

20

L'uso di array_column per reindicizzare ti farà risparmiare tempo se devi trovarlo più volte:

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

Allora puoi semplicemente $lookup[$id]a piacimento.


3
Questa è stata la risposta più sorprendente, anche se non è la più intuitiva ...
Thiago Natanael,

11
class ArrayUtils
{
    public static function objArraySearch($array, $index, $value)
    {
        foreach($array as $arrayInf) {
            if($arrayInf->{$index} == $value) {
                return $arrayInf;
            }
        }
        return null;
    }
}

Usarlo nel modo desiderato sarebbe qualcosa del tipo:

ArrayUtils::objArraySearch($array,'ID',$v);


7

Risolvendo un piccolo errore di @YurkaTim , la tua soluzione funziona per me ma aggiungendo use:

Per utilizzare $searchedValue, all'interno della funzione, una soluzione può essere use ($searchedValue)dopo i parametri della funzionefunction ($e) HERE .

la array_filterfunzione ritorna solo $neededObjectse la condizione al ritorno ètrue

Se $searchedValueè una stringa o un numero intero:

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

Se $searchedValueè un array in cui è necessario verificare con un elenco:

$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

1
Penso che l'ultima riga dovrebbe essere var_dump($neededObject);:)
Sliq

3

A volte mi piace usare la funzione array_reduce () per eseguire la ricerca. È simile a array_filter () ma non influisce sull'array cercato, consentendoti di effettuare più ricerche sullo stesso array di oggetti.

$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): ";
}

1
Hai un refuso all'interno del tuo condizionale in cui stai aggiungendo tot he results_array. Dovrebbe essere questo:if ($current_item->someProperty == $needle){ $result_array[] = $current_item; }
adrum,

Aggiustato. Grazie @adrum!
yuvilio,

1

L'ho fatto con una sorta di keymap Java. In tal caso, non è necessario eseguire il loop sull'array di oggetti ogni volta.

<?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'];

produzione:

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

Ah, reindicizzazione dell'array per id! Lo faccio comunemente e rende le cose più belle.
Kzqai,

1

Modo per ottenere immediatamente il primo valore:

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

0

Ho pubblicato quello che uso per risolvere questo problema in modo efficiente qui utilizzando un rapido algoritmo di ricerca binaria: https://stackoverflow.com/a/52786742/1678210

Non volevo copiare la stessa risposta. Qualcun altro l'aveva chiesto in modo leggermente diverso, ma la risposta è la stessa.

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.