224

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?

1

13 Answers 13

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

Sign up to request clarification or add additional context in comments.

3 Comments

setting $item to null is not needed.
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
For those of you with key values set to strings use if($v == $struct["ID"]){...
106

Use:

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

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

The 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.

10 Comments

Not sure why this isn't the preferred answer. Is it because you are calling two functions?
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.
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'));
This is not the preferred answere because op asks for array of objects and this answere only handle pure arrays.
thats not correct. this code handles array of objects / non flat arrays
|
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;
    }
);

5 Comments

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.
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.
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. :(
TS asked for a single entry, this code returns an array.
YurkaTim's answer 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.
41
+200

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;
    }
);

6 Comments

+1 but array_filter returns an array, and won't stop at the first value found.
It is not recognizing $searchedValue inside the function. But outside it is.
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
In the time of multi cores, this - in other programming environments unfortunately - could be processed in parallel, the loop above not necessarily
To use $searchedValue need write function ($e) use ($searchedValue) {
|
32

Using array_column to reindex will save time if you need to find multiple times:

$lookup = array_column($arr, NULL, 'id'); // Reindex by 'id'

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

Comments

18

Try

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

There is a working example here.

2 Comments

it won't stop at the first found element, will it?
@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.
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);

Comments

7

Fixing a small mistake of YurkaTim's answer (the solution works 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 returns 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 an 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

1 Comment

I think last line should be var_dump($neededObject); :)
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): ";
}

3 Comments

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; }
Adjusted. Thanks @adrum !
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 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!!
2

A way to instantly get the first value:

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

Comments

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)) { ...

3 Comments

Museful's answer 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, 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.
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.
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

2 Comments

Ah, reindexing the array by id! I do this commonly and it makes things nicer.
Museful's later answer accomplishes this in a single line of code, using array_column to re-index. Valid starting with PHP 5.5
-1

Use:

$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;
}

I am working on a WordPress theme to get the total comments from categories, and this helps me out for arrays.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.