PHP: busca la entrada por propiedad de objeto de una matriz de objetos

174

La matriz se ve así:

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

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

Y tengo una variable entera llamada $v.

¿Cómo podría seleccionar una entrada de matriz que tenga un objeto donde la IDpropiedad tenga el $vvalor?

Alex
fuente

Respuestas:

189

Puede iterar la matriz, buscar el registro particular (está bien en una búsqueda única) o construir un hashmap usando otra matriz asociativa.

Para el primero, algo como esto

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

Consulte esta pregunta y las respuestas posteriores para obtener más información sobre este último: referencia de la matriz de PHP por múltiples índices

Phil
fuente
3
No es necesario establecer $ item en nulo.
dAm2K
32
Vaya, ahí está :) Eso es en caso de que el elemento buscado no esté en la matriz. Alternativamente, podría usar, isset($item)pero prefiero inicializar las variables correctamente
Phil
3
Para aquellos de ustedes con valores clave establecidos en cadenas, useif($v == $struct["ID"]){...
wbadart
67

YurkamTim tiene razón. Solo necesita una modificación:

Después de la función ($) necesita un puntero a la variable externa mediante "use (& $ searchingValue)" y luego puede acceder a la variable externa. También puedes modificarlo.

$neededObject = array_filter(
    $arrayOfObjects,
    function ($e) use (&$searchedValue) {
        return $e->id == $searchedValue;
    }
);
Daniel Hardt
fuente
2
Tiene razón sobre la modificación y es un método ordenado, pero probé la velocidad en comparación con la iteración a través del objeto, usted mismo, porque como señaló @phil, array_filter también está haciendo esto, y este método está tomando alrededor de cinco veces más largo Mi objeto de prueba no es grande, por lo que podría empeorar aún más.
Nicolai
9
No &se requiere cuando se importa $searchedValueal alcance del cierre. Se &usa para crear una referencia que solo es necesaria si $searchedValuese ha modificado dentro del cierre.
Stefan Gehrig
Eso es genial. No sabía que PHP podría hacer cosas así. ¡Pensé que usar globalera el único para compartir datos en funciones! Pero es una pena si esto es realmente lento. :(
NoOne
13
TS solicitó una sola entrada, este código devuelve una matriz.
Pavel Vlasov
57
$arr = [
  [
    'ID' => 1
  ]
];

echo array_search(1, array_column($arr, 'ID')); // prints 0 (!== false)
Tim
fuente
3
No estoy seguro de por qué esta no es la respuesta preferida. ¿Es porque estás llamando a dos funciones?
doz87
1
Creo que llegué demasiado tarde a la fiesta;) Su escasez y legibilidad sin ningún bucle ni interrupción lo haría razonable. Pero aún no lo he evaluado. Tienes muchas opciones en PHP para lograr lo mismo.
Tim
3
Solución muy elegante. También funciona con una matriz de objetos en PHP 7. Para PHP 5: array_search ($ object-> id, array_map (function ($ object) {return $ object-> id;}, $ objects)); Para PHP 7: array_search ($ object-> id, array_column ($ objects, 'id'));
Mike
3
Esta no es la respuesta preferida porque op pide una matriz de objetos y esta respuesta solo maneja matrices puras.
Dwza
8
Eso no es correcto. este código maneja una matriz de objetos / matrices no planas
Tim
31

He encontrado una solución más elegante aquí . Adaptado a la pregunta, puede verse así:

$neededObject = array_filter(
    $arrayOfObjects,
    function ($e) use ($searchedValue) {
        return $e->id == $searchedValue;
    }
);
YurkaTim
fuente
16
+1 pero array_filterdevuelve una matriz y no se detendrá en el primer valor encontrado.
Carlos Campderrós
44
No se reconoce $searchedValuedentro de la función. Pero afuera está.
M. Ahmad Zafar
44
Para empezar, este código no funciona ya que $searchedValueestá fuera del alcance del cierre. En segundo lugar, ¿cómo crees que funcionan estos métodos de matriz? Todos recorren la matriz internamente
Phil
1
En el momento de los núcleos múltiples, esto, desafortunadamente en otros entornos de programación, podría procesarse en paralelo, el bucle anterior no necesariamente
FloydThreepwood
3
Para usar $searchedValuenecesita escribirfunction ($e) use ($searchedValue) {
Vilintritenmert
20

El uso de array_column para volver a indexar ahorrará tiempo si necesita buscar varias veces:

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

Entonces puedes simplemente $lookup[$id]a voluntad.

Musculoso
fuente
3
Esta fue la respuesta más sorprendente, incluso si no es la más 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 como quisieras sería algo como:

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

Tratar

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

ejemplo de trabajo aquí

Kamil Kiełczewski
fuente
1
Muy muy útil! ¡Gracias hermano!
Fernando León
no se detendrá en el primer elemento encontrado, ¿verdad?
Yaugenka
7

Arreglando un pequeño error de @YurkaTim , su solución funciona para mí pero agrega use:

Para usar $searchedValue, dentro de la función, una solución puede ser use ($searchedValue)después de los parámetros de la función function ($e) HERE.

la array_filterfunción solo devuelve $neededObjectsi la condición de retorno estrue

Si $searchedValuees una cadena o un entero:

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

Si $searchedValuees una matriz donde necesitamos verificar con una lista:

$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
José Carlos Ramos Carmenates
fuente
1
Creo que la última línea debería ser var_dump($neededObject);:)
Sliq
3

A veces me gusta usar la función array_reduce () para llevar a cabo la búsqueda. Es similar a array_filter () pero no afecta la matriz buscada, lo que le permite realizar múltiples búsquedas en la misma matriz de objetos.

$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
fuente
1
Tiene un error tipográfico dentro de su condicional donde está agregando a la matriz de resultados. Debería ser esto:if ($current_item->someProperty == $needle){ $result_array[] = $current_item; }
Adrum
Equilibrado. Gracias @adrum!
yuvilio
1

Hice esto con algún tipo de mapa de teclas de Java. Si hace eso, no necesita recorrer su matriz de objetos cada vez.

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

salida:

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
fuente
¡Ah, reindexando la matriz por id! Hago esto comúnmente y hace las cosas más agradables.
Kzqai
1

Forma de obtener el primer valor al instante:

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

Publiqué lo que uso para resolver este problema de manera eficiente aquí usando un algoritmo de búsqueda binaria rápida: https://stackoverflow.com/a/52786742/1678210

No quería copiar la misma respuesta. Alguien más lo había preguntado un poco diferente, pero la respuesta es la misma.

Justin Jack
fuente