PHP - znajdź wpis według właściwości obiektu z tablicy obiektów

174

Tablica wygląda następująco:

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

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

I mam zmienną całkowitą o nazwie $v.

Jak mogę wybrać wpis tablicy zawierający obiekt, którego IDwłaściwość ma $vwartość?

Alex
źródło

Odpowiedzi:

189

Albo iterujesz tablicę, wyszukując określony rekord (ok w przypadku tylko jednorazowego wyszukiwania) lub budujesz hashmap używając innej tablicy asocjacyjnej.

Dla tych pierwszych coś takiego

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

Zobacz to pytanie i kolejne odpowiedzi, aby uzyskać więcej informacji na temat tego ostatniego - Odnośnik do tablicy PHP przez wiele indeksów

Phil
źródło
3
ustawienie $ item na null nie jest potrzebne.
dAm2K
32
Ups, oto jest :) To jest na wypadek, gdyby szukanego elementu nie ma w tablicy. Alternatywnie możesz użyć, isset($item)ale ja wolę poprawnie inicjalizować zmienne
Phil
3
Dla tych z Was, którzy mają wartości kluczowe ustawione na ciągi znaków, użyjif($v == $struct["ID"]){...
wbadart
67

YurkamTim ma rację. Potrzebuje tylko modyfikacji:

Po funkcji ($) potrzebujesz wskaźnika do zmiennej zewnętrznej przez „use (& $earchValue)”, a następnie możesz uzyskać dostęp do zmiennej zewnętrznej. Możesz go również zmodyfikować.

$neededObject = array_filter(
    $arrayOfObjects,
    function ($e) use (&$searchedValue) {
        return $e->id == $searchedValue;
    }
);
Daniel Hardt
źródło
2
Masz rację co do modyfikacji i jest to całkiem zgrabna metoda, ale przetestowałem szybkość w porównaniu z iteracją przez obiekt - siebie, ponieważ jak zauważył @phil, array_filter też to robi - a ta metoda zajmuje około pięciu razy dłużej. Mój obiekt testowy nie jest duży, więc może być jeszcze gorzej.
Nicolai,
9
Nie &jest wymagana podczas importowania $searchedValuedo zakresu zamknięcia. &Służy do tworzenia odniesienie, które są potrzebne tylko wtedy, gdy $searchedValuezostał zmodyfikowany wewnątrz zamknięcia.
Stefan Gehrig,
To super. Nie wiedziałem, że PHP może robić takie rzeczy. Myślałem, że używanie globalbyło jedynym sposobem na udostępnianie danych w funkcjach! Ale szkoda, jeśli jest to rzeczywiście powolne. :(
No1
13
TS poprosił o pojedynczy wpis, ten kod zwraca tablicę.
Pavel Vlasov
57
$arr = [
  [
    'ID' => 1
  ]
];

echo array_search(1, array_column($arr, 'ID')); // prints 0 (!== false)
Tim
źródło
3
Nie wiem, dlaczego nie jest to preferowana odpowiedź. Czy to dlatego, że wywołujesz dwie funkcje?
doz87
1
Myślę, że na imprezę było już za późno;) Jej brak i czytelność bez żadnych pętli i przerw sprawiłyby, że byłoby to rozsądne. Ale jeszcze tego nie testowałem. Masz wiele opcji w PHP, aby osiągnąć to samo.
Tim
3
Bardzo eleganckie rozwiązanie. Działa również z tablicą obiektów w PHP 7. Dla PHP 5: array_search ($ object-> id, array_map (function ($ object) {return $ object-> id;}, $ objects)); Dla PHP 7: array_search ($ object-> id, array_column ($ objects, 'id'));
Mike
3
Nie jest to preferowana odpowiedź, ponieważ op pyta o tablicę obiektów, a ta odpowiedź obsługuje tylko czyste tablice.
Dwza
8
to nie jest poprawne. to uchwyty kod tablicę obiektów / Non tablic płaskich
Tim
31

Znalazłam bardziej eleganckie rozwiązanie tutaj . Dostosowany do pytania może wyglądać tak:

$neededObject = array_filter(
    $arrayOfObjects,
    function ($e) use ($searchedValue) {
        return $e->id == $searchedValue;
    }
);
YurkaTim
źródło
16
+1, ale array_filterzwraca tablicę i nie zatrzymuje się na pierwszej znalezionej wartości.
Carlos Campderrós
4
Nie rozpoznaje $searchedValuewewnątrz funkcji. Ale na zewnątrz jest.
M. Ahmad Zafar
4
Na początek ten kod nie działa, ponieważ $searchedValuejest poza zakresem zamknięcia. Po drugie, jak myślisz, jak działają te metody tablicowe? Wszystkie wewnętrzne pętle nad tablicą
Phil
1
W czasach wielordzeniowych, to - niestety w innych środowiskach programistycznych - mogło być przetwarzane równolegle, pętla powyżej niekoniecznie
FloydThreepwood
3
Aby użyć, $searchedValuenapiszfunction ($e) use ($searchedValue) {
Vilintritenmert
20

Użycie kolumny array_column do ponownego indeksowania pozwoli zaoszczędzić czas, jeśli musisz znaleźć wiele razy:

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

Wtedy możesz po prostu $lookup[$id]do woli.

Rozmyślny
źródło
3
To była najbardziej niesamowita odpowiedź, nawet jeśli nie jest najbardziej intuicyjna ...
Thiago Natanael
11
class ArrayUtils
{
    public static function objArraySearch($array, $index, $value)
    {
        foreach($array as $arrayInf) {
            if($arrayInf->{$index} == $value) {
                return $arrayInf;
            }
        }
        return null;
    }
}

Używanie go tak, jak chciałeś, wyglądałoby następująco:

ArrayUtils::objArraySearch($array,'ID',$v);
Pablo SG Pacheco
źródło
9

Próbować

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

przykład pracy tutaj

Kamil Kiełczewski
źródło
1
Bardzo przydatne! Dzięki stary!
Fernando León
nie zatrzyma się na pierwszym znalezionym elemencie, prawda?
yaugenka
7

Naprawiając mały błąd @YurkaTim , twoje rozwiązanie działa dla mnie, ale dodaje use:

Aby użyć $searchedValue, wewnątrz funkcji, jedno rozwiązanie może znajdować się use ($searchedValue)po parametrach funkcji function ($e) HERE.

array_filterfunkcja zwraca tylko na $neededObjectif Warunkiem zwrotu jesttrue

Jeśli $searchedValuejest ciągiem znaków lub liczbą całkowitą:

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

Jeśli $searchedValuejest tablica, w której musimy sprawdzić listę:

$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
źródło
1
Myślę, że ostatnia linijka powinna być var_dump($neededObject);:)
Sliq
3

Czasami lubię używać funkcji array_reduce () do wyszukiwania. Jest podobny do array_filter (), ale nie wpływa na przeszukiwaną tablicę, umożliwiając przeprowadzenie wielu wyszukiwań tej samej tablicy obiektów.

$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
źródło
1
Masz literówkę w swoim warunku, w którym dodajesz do tablicy wyników. Powinno być tak:if ($current_item->someProperty == $needle){ $result_array[] = $current_item; }
adrum
Skorygowana. Dzięki @adrum!
yuvilio
1

Zrobiłem to z jakąś mapą klawiszy Javy. Jeśli to zrobisz, nie będziesz musiał za każdym razem zapętlać swojej tablicy obiektów.

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

wynik:

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
źródło
Ach, ponowne zindeksowanie tablicy według identyfikatora! Robię to często i to sprawia, że ​​wszystko jest przyjemniejsze.
Kzqai,
1

Sposób na natychmiastowe uzyskanie pierwszej wartości:

$neededObject = array_reduce(
    $arrayOfObjects,
    function ($result, $item) use ($searchedValue) {
        return $item->id == $searchedValue ? $item : $result;
    }
);
AndreyP
źródło
0

Opublikowałem tutaj, czego używam do skutecznego rozwiązania tego problemu, używając szybkiego algorytmu wyszukiwania binarnego: https://stackoverflow.com/a/52786742/1678210

Nie chciałem kopiować tej samej odpowiedzi. Ktoś inny zadał to nieco inaczej, ale odpowiedź jest taka sama.

Justin Jack
źródło