223

The array looks like:

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

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

And I have an integer variable called $v.

How could I select an array entry that has an object where the ID property has the $v value?

Dharman
  • 30,962
  • 25
  • 85
  • 135
Alex
  • 66,732
  • 177
  • 439
  • 641

13 Answers13

212

You either iterate the array, searching for the particular record (ok in a one time only search) or build a hashmap using another associative array.

For the former, something like this

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

See this question and subsequent answers for more information on the latter - Reference PHP array by multiple indexes

Community
  • 1
  • 1
Phil
  • 157,677
  • 23
  • 242
  • 245
  • 3
    setting $item to null is not needed. – dAm2K Sep 30 '12 at 20:06
  • 36
    Oops, there it is :) That is in case the sought item is not in the array. Alternatively, you could use `isset($item)` but I prefer initialising variables properly – Phil Oct 01 '12 at 23:41
  • 3
    For those of you with key values set to strings use `if($v == $struct["ID"]){...` – wbadart Jul 07 '15 at 19:32
106
$arr = [
  [
    'ID' => 1
  ]
];

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

Above code echoes the index of the matching element, or false if none.

To get the corresponding element, do something like:

$i = array_search(1, array_column($arr, 'ID'));
$element = ($i !== false ? $arr[$i] : null);

array_column works both on an array of arrays, and on an array of objects.

ToolmakerSteve
  • 18,547
  • 14
  • 94
  • 196
Tim
  • 2,236
  • 1
  • 20
  • 26
  • 5
    Not sure why this isn't the preferred answer. Is it because you are calling two functions? – doz87 Aug 27 '18 at 13:22
  • 2
    I think I was too late for the party ;) Its shortage and readability without any loops and breaks would make it reasonable. But have not benchmarked it yet. You have a lot of of options in PHP to achieve the same. – Tim Sep 03 '18 at 11:24
  • 3
    Very elegant solution. Also works with an array of objects in PHP 7. For PHP 5: array_search($object->id, array_map(function($object) { return $object->id; }, $objects)); For PHP 7: array_search($object->id, array_column($objects, 'id')); – Mike Jan 21 '19 at 12:01
  • 3
    This is not the preferred answere because op asks for array of objects and this answere only handle pure arrays. – Dwza May 12 '19 at 01:30
  • 12
    thats not correct. this code handles array of objects / non flat arrays – Tim May 13 '19 at 11:24
  • Here is a reference to the answer at php documentation: https://www.php.net/manual/en/function.array-search.php#116635 – Rene May 09 '20 at 07:12
  • At first this answer looked wrong to me, but then I realized that it returns the *index*. To get the *element at that index*, do something like: `$i = array_search(...); $element = ($i !== false ? $arr[$i] : null);` Adding that to the answer. – ToolmakerSteve Dec 23 '20 at 20:45
  • 1
    This requires the properties in the object to be public. This is the case in the mentioned problem, but for other users with named classes and private properties, this solution wont work. – galmok Jan 20 '21 at 08:04
  • This is the most preferred solution in PHP context. but the solution above is applicable across all programming language. – Nilesh K Apr 17 '21 at 09:50
  • I think this should be the accepted answer. Simple, concise and most importantly; gets the job done – Oluwaseyitan Baderinwa Jan 13 '22 at 01:54
77

YurkamTim is right. It needs only a modification:

After function($) you need a pointer to the external variable by "use(&$searchedValue)" and then you can access the external variable. Also you can modify it.

$neededObject = array_filter(
    $arrayOfObjects,
    function ($e) use (&$searchedValue) {
        return $e->id == $searchedValue;
    }
);
Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
Daniel Hardt
  • 801
  • 6
  • 6
  • 3
    You're right about the modification and it is kind of a neat method, but I tested the speed compared to iterating through the object - yourself, because like @phil pointed out, array_filter is doing this too - and this method is taking about five times longer. My test object isn't a big one, so that might get even worse. – Nicolai Grossherr Jan 05 '14 at 19:46
  • 12
    The `&` is not required when importing `$searchedValue` into the closure scope. The `&` is used to create a reference which is only needed if `$searchedValue` has been modified inside the closure. – Stefan Gehrig Jan 07 '16 at 10:08
  • That's cool. I didn't know PHP could do things like that. I thought using `global` was the only was to share data in functions! But it's a pity if this is indeed slow. :( – NoOne Jan 23 '16 at 16:18
  • 15
    TS asked for a single entry, this code returns an array. – Pavel Vlasov Feb 28 '17 at 17:53
  • [YurkaTim's answer](https://stackoverflow.com/a/17694792/199364) has been updated to include `use ($searchedValue)`. As StefanGehrig says in his comment, you don't need `&` i.e. `use (&$searchedValue)` unless you need to *modify* $searchedValue. – ToolmakerSteve Dec 23 '20 at 20:29
41

I've found more elegant solution here. Adapted to the question it may look like:

$neededObject = array_filter(
    $arrayOfObjects,
    function ($e) use ($searchedValue) {
        return $e->id == $searchedValue;
    }
);
AndreyP
  • 2,510
  • 1
  • 29
  • 17
YurkaTim
  • 681
  • 5
  • 7
  • 27
    +1 but `array_filter` returns an array, and won't stop at the first value found. – Carlos Campderrós Jul 17 '13 at 08:43
  • well, it depends ;) if I have array of few items I'd prefer array_filter over hand made loop, considering it's built in php function. – YurkaTim Jul 17 '13 at 09:28
  • 4
    It is not recognizing `$searchedValue` inside the function. But outside it is. – M. Ahmad Zafar Jul 30 '13 at 23:52
  • 4
    For starters, this code doesn't work as `$searchedValue` is outside of the closure scope. Secondly, how do you think these array methods work? They all loop over the array internally – Phil Jul 31 '13 at 03:36
  • 1
    In the time of multi cores, this - in other programming environments unfortunately - could be processed in parallel, the loop above not necessarily – FloydThreepwood Oct 29 '15 at 17:56
  • 4
    To use `$searchedValue` need write `function ($e) use ($searchedValue) { ` – Vilintritenmert Mar 26 '19 at 12:58
31

Using array_column to re-index will save time if you need to find multiple times:

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

Then you can simply $lookup[$id] at will.

Museful
  • 6,711
  • 5
  • 42
  • 68
17

Try

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

working example here

Kamil Kiełczewski
  • 85,173
  • 29
  • 368
  • 345
  • it won't stop at the first found element, will it? – yaugenka Mar 20 '20 at 18:22
  • @yaugenka - correct, it first creates an array containing all the matches. Then `current` returns the first one, or `false` if there are no matches. [Recommend testing result using `=== false`, not `== false`.] IMHO, this use of `current` is a bit obscure. OTOH, it is well-defined and documented. – ToolmakerSteve Dec 23 '20 at 20:35
14
class ArrayUtils
{
    public static function objArraySearch($array, $index, $value)
    {
        foreach($array as $arrayInf) {
            if($arrayInf->{$index} == $value) {
                return $arrayInf;
            }
        }
        return null;
    }
}

Using it the way you wanted would be something like:

ArrayUtils::objArraySearch($array,'ID',$v);
Pablo S G Pacheco
  • 2,550
  • 28
  • 28
7

Fixing a small mistake of the @YurkaTim, your solution work for me but adding use:

To use $searchedValue, inside of the function, one solution can be use ($searchedValue) after function parameters function ($e) HERE.

the array_filter function only return on $neededObject the if the condition on return is true

If $searchedValue is a string or integer:

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

If $searchedValue is array where we need check with a 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
3

I sometimes like using the array_reduce() function to carry out the search. It's similar to array_filter() but does not affect the searched array, allowing you to carry out multiple searches on the same array of objects.

$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
  • 3,795
  • 32
  • 35
  • 1
    You have a typo inside your conditional where you're adding tot he results_array. It should be this: ```if ($current_item->someProperty == $needle){ $result_array[] = $current_item; }``` – adrum Feb 28 '17 at 14:47
  • Adjusted. Thanks @adrum ! – yuvilio Feb 28 '17 at 22:00
  • Re *"It's similar to array_filter() but does not affect the searched array, allowing you to carry out multiple searches"*: You seem to be under the mistaken impression that `array_filter` modifies the original array. It does not. Your function to create a $result_array is exactly what array_filter already does! [AndreyP's later answer](https://stackoverflow.com/a/55515785/199364) is the efficient way to use `array_reduce`; I see no circumstance in which this answer is useful - just use AndreyP's answer. If you want to stop at the first item, then write a function that stops at the first item!! – ToolmakerSteve Dec 23 '20 at 19:57
2

Way to instantly get first value:

$neededObject = array_reduce(
    $arrayOfObjects,
    function ($result, $item) use ($searchedValue) {
        return $item->id == $searchedValue ? $item : $result;
    }
);
AndreyP
  • 2,510
  • 1
  • 29
  • 17
1

I did this with some sort of Java keymap. If you do that, you do not need to loop over your objects array every time.

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

output:

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
  • 47
  • 10
  • Ah, reindexing the array by id! I do this commonly and it makes things nicer. – Kzqai Jul 05 '16 at 16:18
  • [Museful's later answer](https://stackoverflow.com/a/44167939/199364) accomplishes this in a single line of code, using `array_column` to re-index. Valid starting with PHP 5.5 – ToolmakerSteve Dec 23 '20 at 20:04
1

I solved this problem by keying the array with the ID. It's simpler and possibly faster for this scenario where the ID is what you're looking for.

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

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

Now I can directly address the array:

$array[$v]->name = ...

Or, if I want to verify the existence of an ID:

if (array_key_exists($v, $array)) { ...
Chad E.
  • 1,196
  • 9
  • 12
  • 1
    [Museful's answer](https://stackoverflow.com/a/44167939/199364) shows how to accomplish this, for an existing array, using `array_column`. Its generally preferable to do what he shows, as that also includes the `id` value as part of the object. For example, if the object is passed to another function, the `id` does not need to be separately passed. – ToolmakerSteve Dec 23 '20 at 20:06
  • @ToolmakerSteve, I did see that Museful used array_column. I offered this solution, because respectfully, I'll argue that array_column is generally not preferable in busy applications for a couple reasons. First, re-indexing an array of objects rather than simply keying the data as it's loaded is CPU wasteful. Second, storing ID twice is memory wasteful. Why not just pass the ID, and let my external function reference the existing array? Passing an object doesn't clone it, so if I truly need a clone, I could add the ID at that point. – Chad E. Dec 25 '20 at 01:59
  • I agree that if you have control over building the data in the first place, then `array_column` is not needed, so its cost is a moot point. I would key by id at that time, of course. Just be aware that if you ever find yourself needing to pass id *with* the other data, the optimal change is to accept the duplication of id, and add that id into the built data - rather than making some other change later in the data flow. The memory cost of duplicating id is negligible, and should not influence design decisions. – ToolmakerSteve Jan 06 '21 at 23:02
-1
      $keyToLookFor = $term->name;
      $foundField = array_filter($categories, function($field) use($keyToLookFor){
      return $field -> name === $keyToLookFor; });

      if(!empty($foundField)){
      $ke = array_keys($foundField);
      $ke = $ke[0];
      $v = $foundField[$ke]->id;}

Am Working On Wordpress Theme Get Total Comment from Catagories And This help me out for Arrays