12

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.

5
  • Well, for one if the array was formed differently like this -> ['a' => $obj] you'd only need to check if it's set and set the value:if(isset($objs['a']))$objs['a']['value'] = $value; Commented Oct 27, 2018 at 16:37
  • 1
    I had it as that before, but since this array if formed from JSON, the order of the objects isn't respected. So I had to add an index to each object, and the value and key with that. Commented Oct 27, 2018 at 16:49
  • Your json is invalid. Post something that works Commented Oct 27, 2018 at 19:46
  • 1
    In my opinion, your question has already been solved in many ways; choose any and adapt the logic of your application to your chosen solution. So change it, for example, add an order field to the object. It is not clear what you want from the community) Commented Oct 27, 2018 at 19:55
  • @Andreas How is it invalid? Unless you're talking about the missing quotes around 'value' in the first case, which was a typo easily fixed. But your answer helped me so I will accept it as the right approach. Thanks. Commented Oct 28, 2018 at 14:01

4 Answers 4

15

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.

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

6 Comments

Mind that array_search returns false if not found which will mess up the array. 3v4l.org/Lc2Dd p.s. it's the value that OP wants to update not the key.
You are absolutely correct with regards to array_search() returning false. That said, this will update its value, not the key (as you can see in the demo as well).
It does update the "key", not the value. And as you can see in my demo it updates the wrong item. It should not update any in my example yet it updates "key a"
Whoops, I got confused with the index names key/value, and that they are in fact, keys and values. I'll update it. Thanks!
costing the same as a for loop no?
|
2

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

1 Comment

How is this "more efficient" than looping over the array and updating when you run into an object?
2

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

8 Comments

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.
@fractal5 I don't understand what you are saying. All arrays have indexes or associative keys. It seems you are trying to get the answer on another question here.
@Andreas No, he is mean what can't use key field as an index of an array.
But there is no explanation of why. I have not seen any good reason to why he can't use that.
I change code above. What about that? Of course @Andreas is right: not enough data ))))
|
0

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.

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.