0

I have an array like this:

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

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

I found some solution to search using loop like this:

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

Because of the large amount of data, I want to change it so that I can retrieve multiple values ​​instead of one value at a time (ex: $array->420 = Mary, $array->10957 = Blah,...). Which way would be the most optimal in this case?

Mido
  • 341
  • 2
  • 15
  • 1
    Collect those values in a new array. – nice_dev Nov 25 '19 at 07:47
  • 1
    If you IDs are unique, then I would replace the keys of the original array with them, so that you can then access `$array[420]` directly, or use `isset` to see if a particular key is set, when you need to find if an element with a specific ID exists. A combination of array_combine and array_column helps modify the array accordingly. – 04FS Nov 25 '19 at 07:47
  • Looks similar to this: https://stackoverflow.com/q/4742903/2943403 (attribution is nice) – mickmackusa Nov 25 '19 at 07:55
  • Do your objects have only an ID and a name? Or do you have more stuff in there that you need (that you omitted for the question)? – Jeto Nov 25 '19 at 07:56
  • Looks like you want the inverse of this: https://stackoverflow.com/q/25994438/2943403 – mickmackusa Nov 25 '19 at 08:07
  • It's exactly stackoverflow.com/q/4742903/2943403 . But it doesn't look good in my case because I need to get a lot of value. To make it easier to understand, I have omitted the unnecessary things in the table – Mido Nov 25 '19 at 08:07

2 Answers2

1

If you index your main array by the ID (use array_column() for this), and an array of the ID's you are after, then array_intersect_key() will extract all of the ones you want into a list of the matches...

$array =[
    (Object)
    [
        "ID" => 420,
        "name" => "Mary"
        ],

    (Object)
    [
        "ID" => 10957,
        "name" => "Blah"
    ]
];

$ids = [420, 10957];

$indexArray = array_column($array, null, "ID" );
$matches = array_intersect_key($indexArray, array_flip($ids));
print_r($matches);

gives..

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

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

)

You need to use array_flip() on the ID's array to convert the value into the key to work with the array_intersect_key() function.

You can then use array_values() if you don't want the key for this data (i.e. the ID)

Nigel Ren
  • 56,122
  • 11
  • 43
  • 55
  • "**Which way would be the most optimal in this case?**" For the record, this makes two passes over the input, which will be less efficient than a single foreach loop. Code brevity is the benefit to this snippet. – mickmackusa Nov 25 '19 at 07:58
  • @mickmackusa I need get multiple value, and i dont want foreach loop whole array for each value. – Mido Nov 25 '19 at 08:20
1

Here's three possible solutions depending on your needs, using array_column:

Build an ID => name array:

$result = array_column($array, 'name', 'ID');

Build an ID => entry array (if you have more stuff than just the name):

$result = array_column($items, null, 'ID');

Alternative using array_reduce:

$result = array_reduce($array, static function ($result, $item) {
  $result[$item['ID']] = $item;
  return $result;
});

Demo: https://3v4l.org/fLMgL

Jeto
  • 14,596
  • 2
  • 32
  • 46
  • 1
    I always disagree with `array_combine(array_column($array, 'ID'), $array);` every time I see it. Learn from Nigel's array_column() call. – mickmackusa Nov 25 '19 at 08:08
  • @mickmackusa That's right, I seem to always forget about that use of the function (which is handy but quite inintuitive to me). Edited my post accordingly. – Jeto Nov 25 '19 at 09:11