Remove Object from array by object value in php - php

$followers = [['id'=>0], ['id'=>1]];
So, assuming I have this array, what would be the best way to remove the object by it's id?
That's what i came up with
foreach($followers as $key=>$follower){
if($follower->id == 0){unset $followers[$key]}
}
is there a better more efficient way?

It is an array not an object, so why are you accessing as an object?
Try this,
foreach ($followers as $key => $follower) {
if($followers[$key] == 0) {
unset($followers[$key]);
}
}
You were accessing values of an array like an object.
You were using unset incorrectly.
You were missing the ; at the end of your unset part.

What I really need is removing an item from array of arrays in my Cache I tried this:
if(Cache::has('user_follower'.$user_id)){
$user_follower = Cache::get('user_follower'.$user_id);
foreach($user_follower as $key=>$follower){
if($follower->user_id == Auth::id()){
unset($user_follower[$key]);
Cache::put('user_follower'.$user_id, $user_follower, 30);
return;
}
}
}
I failed sadly, so I'm for now I'm using Cache::forget.

Related

Remove first element from simple array in loop

This question has been asked a thousand times, but each question I find talks about associative arrays where one can delete (unset) an item by using they key as an identifier. But how do you do this if you have a simple array, and no key-value pairs?
Input code
$bananas = array('big_banana', 'small_banana', 'ripe_banana', 'yellow_banana', 'green_banana', 'brown_banana', 'peeled_banana');
foreach ($bananas as $banana) {
// do stuff
// remove current item
}
In Perl I would work with for and indices instead, but I am not sure that's the (safest?) way to go - even though from what I hear PHP is less strict in these things.
Note that after foreach has run, I expected var_dump($bananas) to return an empty array (or null, but preferably an empty array).
1st method (delete by value comparison):
$bananas = array('big_banana', 'small_banana', 'ripe_banana', 'yellow_banana', 'green_banana', 'brown_banana', 'peeled_banana');
foreach ($bananas as $key=>$banana) {
if($banana=='big_banana')
unset($bananas[$key]);
}
2nd method (delete by key):
$bananas = array('big_banana', 'small_banana', 'ripe_banana', 'yellow_banana', 'green_banana', 'brown_banana', 'peeled_banana');
unset($bananas[0]); //removes the first value
unset($bananas[count($bananas)-1]); //removes the last value
//unset($bananas[n-1]); removes the nth value
Finally if you want to reset the keys after deletion process:
$bananas = array_map('array_values', $bananas);
If you want to empty the array completely:
unset($bananas);
$bananas= array();
it still has the indexes
foreach ($bananas as $key => $banana) {
// do stuff
unset($bananas[$key]);
}
for($i=0; $i<count($bananas); $i++)
{
//doStuff
unset($bananas[$i]);
}
This will delete every element after its use so you will eventually end up with an empty array.
If for some reason you need to reindex after deleting you can use array_values
How about a while loop with array_shift?
while (($item = array_shift($bananas)) !== null)
{
//
}
Your Note: Note that after foreach has run, I expected var_dump($bananas) to return an empty array (or null, but preferably
an empty array).
Simply use unset.
foreach ($bananas as $banana) {
// do stuff
// remove current item
unset($bananas[$key]);
}
print_r($bananas);
Result
Array
(
)
This question is old but I will post my idea using array_slice for new visitors.
while(!empty($bananas)) {
// ... do something with $bananas[0] like
echo $bananas[0].'<br>';
$bananas = array_slice($bananas, 1);
}

Setting an array value in multi-dimensional arrays PHP

I have the following problem:
I have an array of arrays with unknown amount of subarrays so my array might look like this:
array('element1'=>array('subelement1'=>'value'
'subelement2'=>array(...),
'element2'=>array('something'=>'this',
'subelement1'=>'awesome'));
Now I want to write a function that is able to replace a value by having it's path in the array, the first parameter is an array that defines the keys to search for. If I want to replace 'value' in the example with 'anothervalue', the function call should look like this:
replace_array(array('element1','subelement1'),'anothervalue');
It should also be able to replace all values on a given level by using null or another placeholder e.g.
replace_array(array(-1, 'subelement1'),'anothervalue');
should replace both 'value' and 'awesome'.
I tried to get it work by using a recursive function and references (one call searches the first array by using the first element in the path variable, and then it calls itself again with the subarray until it has found all occurences defined by the given path).
Is there a smart way to get it done? As my reference idea doesn't seem to work that good.
I can post the code I'm using atm later on.
Thank you.
edit: I updated my answer to also do -1
edit: As -1 is valid for use as an array key, I think you shouldn't use that to mark "all" keys. Arrays themselves however cannot be used as an array key. So in stead of -1 , I have chosen to use an array ([] or array()) to mark "all" keys.
function replace_array(&$original_array, $path, $new_value) {
$cursor =& $original_array;
if (!is_array($path))
return;
while($path) {
$index = array_shift($path);
if (!is_array($cursor) || (!is_array($index) && !isset($cursor[$index])))
return;
if (is_array($index)) {
foreach($cursor as &$child)
replace_array($child, $path, $new_value);
return;
} else {
$cursor =& $cursor[$index];
}
}
$cursor = $new_value;
return;
}
// use like : replace_array($my_array, array("first key", array(), "third key"), "new value");
// or php5.4+ : replace_array($my_array, ["first key", [], "third key"], "new value");
The key in constructing this method lies in passing the array by reference. If you do that, the task becomes quite simple.
It is going to be a recursive method, so the questions to ask should be:
Is this the last recursion?
What key do I have to look for in this level?
array_shift() comes in handy here as you get the first level and at the same moment shorten the $searchPath properly for the next recursion.
function deepReplace($searchPath, $newValue, &$array) {
// ^- reference
//Is this the last recursion?
if (count($searchPath) == 0) {
$array = $newValue;
}
if (!is_array($array))
return;
//What key do I have to look for in this level?
$lookFor = array_shift($searchPath);
//To support all values on given level using NULL
if ($lookFor === null) {
foreach ($array as &$value) {
// ^- reference
deepReplace($searchPath, $newValue, $value);
}
} elseif (array_key_exists($lookFor, $array)) {
deepReplace($searchPath, $newValue, $array[$lookFor]);
}
}
See it work here like
deepReplace(array(null, "subelement1"), "newValue", $data);
deepReplace(array("element1", "subelement1"), "newValue", $data);

Unset value (with unknown index) from array without iterating

I want to unset a known value from an array. I could iterate with a for loop to look for the coincident value and then unset it.
<?php
for($i=0, $length=count($array); $i<$length; $i++)
{
if( $array[$i] === $valueToUnset )
//unset the value from the array
}
Any idea? Any way to achieve it without looping?
I am presuming that your intention is to get the index back, as you already have the value. I am further presuming that there is also a possibility that said value will NOT be in the array, and we have to account for that. I am not sure what you are using array_slice for. So, if I properly understand your requirements, a simple solution would be as follows:
<?php
$foundIndex = false; //Initialize variable that will hold index value
$foundIndex = array_search($valueToExtract, $array);
if($foundIndex === null) {
//Value was not found in the array
} else {
unset($array[$foundIndex]; //Unset the target element
}
?>
array_diff is the solution:
<?php
array_diff($array, array($valueToUnset));
No iteration needed.

multi-dimensional stdClass Object

I've got a rather large multidimensional stdClass Object being outputted from a json feed with PHP.
It goes about 8 or 9 steps deep and the data that I need is around 7 steps in.
I'm wondering if I can easily grab one of the entires instead of doing this:
echo $data->one->two->anotherone->gettinglong->omg->hereweare;
I'm saying this because the data structure may change over time.
Is this possible?
You could try to parse the object into an array and search the array for the wanted values, it just keeps looping through each level of the object.
function parseObjectArrayToArray($objectPassed, &$in_arr = array()) {
foreach($objectPassed as $element) {
if(is_object($element) || is_array($element)) {
parseObjectArrayToArray($element,$in_arr);
} else {
// XML is being passed, need to strip it
$element = strip_tags($element);
// Trim whitespace
$element = trim($element);
// Push to array
if($element != '' && !in_array($element,$in_arr)) {
$in_arr[] = $element;
}
}
}
return $in_arr;
}
How to call
$parsed_obj_arr = parseObjectArrayToArray($objectPassed);
Not without searching through whats probably inefficient.
Json is a structured data object with the purpose of eliminating something like this.
If the datastructure can change, but doesn't very often, your best bet is to write a wrapper object so you will only have to change a path at a single point on change:
class MyDataWrapp {
public $json;
function __construct($jsonstring){
$this->json = json_decode($jsonstring);
}
function getHereWeAre(){
return $this->json->one->two->anotherone->gettinglong->omg->hereweare;
}
}
If the datastructure changes dramatically and constantly, I'd json_decode as an array of arrays, and probably use RecursiveFilterIterator.

How do you remove an array element in a foreach loop?

I want to loop through an array with foreach to check if a value exists. If the value does exist, I want to delete the element which contains it.
I have the following code:
foreach($display_related_tags as $tag_name) {
if($tag_name == $found_tag['name']) {
// Delete element
}
}
I don't know how to delete the element once the value is found. How do I delete it?
I have to use foreach for this problem. There are probably alternatives to foreach, and you are welcome to share them.
If you also get the key, you can delete that item like this:
foreach ($display_related_tags as $key => $tag_name) {
if($tag_name == $found_tag['name']) {
unset($display_related_tags[$key]);
}
}
A better solution is to use the array_filter function:
$display_related_tags =
array_filter($display_related_tags, function($e) use($found_tag){
return $e != $found_tag['name'];
});
As the php documentation reads:
As foreach relies on the internal array pointer in PHP 5, changing it within the loop may lead to unexpected behavior.
In PHP 7, foreach does not use the internal array pointer.
foreach($display_related_tags as $key => $tag_name)
{
if($tag_name == $found_tag['name'])
unset($display_related_tags[$key];
}
Instead of doing foreach() loop on the array, it would be faster to use array_search() to find the proper key. On small arrays, I would go with foreach for better readibility, but for bigger arrays, or often executed code, this should be a bit more optimal:
$result=array_search($unwantedValue,$array,true);
if($result !== false) {
unset($array[$result]);
}
The strict comparsion operator !== is needed, because array_search() can return 0 as the index of the $unwantedValue.
Also, the above example will remove just the first value $unwantedValue, if the $unwantedValue can occur more then once in the $array, You should use array_keys(), to find all of them:
$result=array_keys($array,$unwantedValue,true)
foreach($result as $key) {
unset($array[$key]);
}
Check http://php.net/manual/en/function.array-search.php for more information.
if you have scenario in which you have to remove more then one values from the foreach array in this case you have to pass value by reference in for each:
I try to explain this scenario:
foreach ($manSkuQty as $man_sku => &$man_qty) {
foreach ($manufacturerSkus as $key1 => $val1) {
// some processing here and unset first loops entries
// here dont include again for next iterations
if(some condition)
unset($manSkuQty[$key1]);
}
}
}
in second loop you want to unset first loops entries dont come again in the iteration for performance purpose or else then unset from memory as well because in memory they present and will come in iterations.
There are already answers which are giving light on how to unset. Rather than repeating code in all your classes make function like below and use it in code whenever required. In business logic, sometimes you don't want to expose some properties. Please see below one liner call to remove
public static function removeKeysFromAssociativeArray($associativeArray, $keysToUnset)
{
if (empty($associativeArray) || empty($keysToUnset))
return array();
foreach ($associativeArray as $key => $arr) {
if (!is_array($arr)) {
continue;
}
foreach ($keysToUnset as $keyToUnset) {
if (array_key_exists($keyToUnset, $arr)) {
unset($arr[$keyToUnset]);
}
}
$associativeArray[$key] = $arr;
}
return $associativeArray;
}
Call like:
removeKeysFromAssociativeArray($arrValues, $keysToRemove);

Categories