PHP - Find an object by key in an array of objects, update its value

Viewed 8861

I have an array of objects, and want to update an attribute of one of the objects.

$objs = [ 
    ['value' => 2, 'key' => 'a'], 
    ['value' => 3, 'key' => 'b'] ,
];

Let's say I want to set the 'value' of the object with 'key'=>'a' to 5.

Aside from iterating over the array searching for the key, is there any quicker/efficient way of doing this?

Thanks.

EDIT: There is debate as to why I can't use an associative array. It is because this array is obtained from a JSON value.

If my JSON object is this:

"obj": {
    "a": {
        "key": "a", 
        "value": 2
    }, 
    "b": {
        "key": "b", 
        "value": 3
    }
}

There is no guarantee that the order of the objects will be retained, which is required.

Hence I need an index in each object to be able to sort it using usort(). So my JSON needs to be:

"obj": {
    "a": {
        "key": "a", 
        "value": 2, 
        "index": 1
    }, 
    "b": {
        "key": "b", 
        "value": 3, 
        "index": 2
    }
}

But I cannot use usort() on an object, only on arrays. So my JSON needs to be

"obj": [
    {
        "key": "a", 
        "value": 2, 
        "index": 1
    }, {
        "key": "b", 
        "value": 3, 
        "index":2
    }
]

Which brings us to the original question.

4 Answers

By using array_column(), you can pull all the values with the index key in the arrays. Then you can find the first occurrence of the value a by using array_search(). This will only return the first index where it finds a value. Then you can simply replace that value, as you now have the index of that value.

$keys = array_column($objs, 'key');
$index = array_search('a', $keys);

if ($index !== false) {
    $objs[$index]['value'] = 5;
}

See this live demo.

You can make the array associative with array column. That way you can directly assign the value.

$objs = [ ['value'=>2, 'key'=>'a'], ['value'=>3, 'key'=>'b'] ];
$objs = array_column($objs, null, "key");
$objs['a']['value'] = 5;

https://3v4l.org/7tJl0

I want to recommend you reorginize your array lake that:

$objs = [ 
'a' => ['value'=>2, 'key'=>'a'], 
'b' => ['value'=>3, 'key'=>'b'] 
];

And now

if( array_key_exists( 'a', $objs )) {
  $objs ['a'] ['value'] = 5;
}

I had it like that initially. But I need for the objects to have an index value in them, so I can run usort() on the main array. This is because the array comes from JSON where the original order isn't respected

Then create an index array:

// When fill `$objs` array
$objs = [];
$arrIndex = [];
$idx = 0;
foreach( $json as $item ) {
  $arrIndex [ $item ['key']] = $idx;
  $objs [$idx ++] = $item;
}

// And your task:

if( array_key_exists( 'a', $arrIndex )) {
  $objs [ $arrIndex ['a']] ['value'] = 5;
}

Aside from iterating over the array searching for the key, is there any quicker/efficient way of doing this?

You have to pay the price of iteration either way.

You can search your collection for the interesting object (takes linear time), or you form some kind of dictionary data structure, e.g. hash table (takes linear time) and then find the interesting object in constant time.

No free lunches here.

Related