How to delete array element by index - php

Is there any possible way to delete element from array? It is shopping cart storing item IDs. I want to make delete function.
For example - cart_handler.php?delete=2687
array(5) { [1967]=> float(1) [1966]=> float(1) [2233]=> float(5) [2687]=> float(1) [2081]=> float(4) }

Yes you can, the easiest way would be to search for the item ID in the array, and then unset the key associated with it -- and then as an extension you could re-base the array to fix the array keys. Please Note: I haven't put any validation on the $arrayKey and what it returns, you should ensure that the array_search function is returning as expected before unsetting the array key just to be safe.
So something like this:
$data = [1967, 1966, 2233, 2687, 2081];
$arrayKey = array_search(1966, $data);
unset($data[$arrayKey]);
The specified product ID would be unset by that, just replace 1966 with your $_GET variable. i.e.
array_search($_GET['delete'], $data)
And the $data array would be a list of all your valid product IDs, that you could pull out from your database, or wherever you are storing them.
If you want to re-base the key indexes after this you can do:
$data = array_values($data);
What the above does is fixes the array key indexes, when you unset an element it will be removed from the array, but all keys will maintain their current indexes. So the array indexes may progress like so: 0, 1, 3, 4. If you re-base the array with the above they'll progress naturally again: 0, 1, 2, 3.
Hope that helps, any questions just let me know.

Related

Sorting loosely connected data reminiscent of a singly linked list

I am looking for an efficient solution to sorting linked data.
This is the context:
A program returns an array of objects each containing two variables: id and previous_id. The id is an unique identifier and the previous_id refers to another id of an object in the array. The order of the objects in the array is random.
The obvious ordering is of course this: In the sorted array the first object is the one where the previous_id is null. The next object in the array should always be the object whose previous_id corresponds with the id of the current object, or it is the last object.
What is an efficient algorithm to sort these variables in the above mentioned ordering?
My intuition suggests there is a simple way to sort these variables. The way these objects are represented reminds me of a singly linked list. Yet I can't seem to find an elegant solution to this.
My current algorithm is overly complex and works like this:
First we prepare the array for sorting by building a hash map of
arrays. The hashmap is built by iterating over the array and mapping
the key to the id of the current object and the value to the current
object, wrapped in an array of size 1.
The goal of these arrays is to always have the correct ordering,
except the first element, which can have a previous_id that may point
to an element which is not in it's own array, or be null.
The key pointing to this array in the hash map is always the id of the last element in the array.
We then keep looping over the hashmap until the length of the hashmap
is less or equal to 1.
In the loop we iterate over the the hashmap.
If the key of the current hash item is not null, we take the first
element of the array which we will call head. We also take the last element of the array, which we call butt.
We can now merge two arrays into one by taking the array found in the hash map whose key is equal to the head's previous_id with current array in the iteration and deleting the found array in the hashmap.
The pseudocode is like this:
$tbr = $this->prepareDataForSorting();
while (count($tbr) > 1) {
foreach ($tbr as $key => $children) {
$head = array_first($children);
if ($head->previousId !== null) {
$butt = array_last($children);
$tbr[$butt->id] = array_merge($tbr[$head->previousId], $children);
unset($tbr[$head->previousId]);
}
}
}
return $tbr[array_key_first($tbr)];
Where the prepare for sorting procedure is implemented like this:
$tbr = [];
foreach ($this->children as $child) {
$tbr[$child->id] = [$child];
}
return $tbr;
The problem I have with this algorithm is that is not not lightweight at all. It requires hash maps as an auxiliary data structure as well as an O(n^2) algorithm. I feel there should be a much simpler way.
The answer has been posted below. I decided to include it's php implementation for future visitors:
$mapping = $this->mapData();
$current = $mapping[null] ?? null;
$tbr = [];
while ($current !== null) {
$tbr[] = $current;
$current = $mapping[$current->id] ?? null;
}
return $tbr;
With map data:
$tbr = [];
foreach ($this->children as $child) {
$tbr[$child->previousId] = [$child];
}
return $tbr;
simply beautiful
You can achieve what you want in better and more simpler way.
My suggestion is as follows:
Create a hash map
Iterate over array and for each and every entry in the array, create an entry in hash map whose key and value are previous_id and current entry in the iteration, respectively.
Finally, you need to get hash value of key null (because your first item's previous_id is null), push its value to final array, and use the id of current entry as new key for hashmap.
Do the last step until the length of final array be the same as original array.
Complexity of this approach is O(n) which is very effecient in comparision with O(n^2)

Need to unset a specific session array

I have set an array to a session variable using key-value pairs, but I need to unset that specific session when I click on the delete button.
This is the code that stores the session variables:
$_SESSION['product'][] = array(
'product_id' => $part_id,
'title' => $title,
'price' => $price,
'default_img' => $default_img,
'quantity' => $quantity);
And here's the code that unsets the session:
if (isset($_POST['removeItem'])) {
$prodId=$_SESSION['prodItemId'];
foreach($_SESSION['product'] as $item) {
if ($_GET["partid"] == $item['product_id']) {
unset($_SESSION["product"]);
}
The problem I'm having is that instead of just unsetting one session instance, it unsets the entire session. I've tried unset($_SESSION["product"][$item]);
You tell the code to unset the whole session, so it does.
Include the key in the foreach and unset the specific key that you need to unset.
foreach($_SESSION['product'] as $key => $item) {
if ($_GET["partid"] == $item['product_id']) {
unset($_SESSION["product"][$key]);
}
}
You could also search for the specific value and skip the whole loop thing.
if (isset($_POST['removeItem'])) {
$prodId=$_SESSION['prodItemId'];
$key = array_search($_GET["partid"], array_column($_SESSION['product'], 'product_id'));
if($key !== false) unset($_SESSION["product"][$key]);
}
Array_search searches for the GET partid and if it's found it returns the key of where it is, else it returns false.
If you have multiple array items that need to be removed the above array_search method will only remove the first.
You can however loop the array_search to get them all.
if (isset($_POST['removeItem'])) {
$prodId=$_SESSION['prodItemId'];
$prodID = array_column($_SESSION['product'], 'product_id'); // creates a flat array that can be searched
while($key = array_search($_GET["partid"], $prodID)){
unset($_SESSION["product"][$key]);
}
}
Here we search to see if there is a matching value, if there is we delete the key, then the while loop searches again.
If a new matching value is forum it's deleted, if not array_search will return false and break the while loop.
A fourth method is to almost keep the code you have as it is, but loop the array by reference with & and unset the item.
foreach($_SESSION['product'] as &$item) { // notice the &
if ($_GET["partid"] == $item['product_id']) {
unset($item); //because we used &, we can now unset $item
}
}
A fifth method is to use array_diff and array_intersect.
This method is the slowest and should not be used on larger arrays, it can be used with very little difference on smaller arrays (less than 50-100 items).
if (isset($_POST['removeItem'])) {
$prodId=$_SESSION['prodItemId'];
$_SESSION['product'] = array_intersect_key($_SESSION['product'], array_diff(array_column($_SESSION['product'], 'product_id'), $_GET["partid"]));
}
In order to explain it I need to explain it in "reverse" order from what you read it since it's nested.
I start with created a flat array with array_column.
This array only contains the productid's.
I use array_diff to return only the items that is not matching $_GET["partid"].
What we get is a flat array with only the productid's. That may sound useless, and it is, but the keys is useful.
The keys match what is in the session array.
So if we use array_intersect_key and use $_SESSION['product'] as the main array and the keys from the array_diff then the output is the items in $_SESSION['product'] that does not match $_GET["partid"].
It's complicated in the background but it's a simple on liner.

Delete one item from array with matching keys

I have an array
$array = ['f'=>'foo', 'f'=>'foo', 'f'=>'foo','g'=>'good'];
and I want to delete only one item from this array with matching key, like the following:
unset($array['f']);
However, this will delete the all items with this matching key 'f' and only one item will remain. Is there a way to do something like this, but apply it only to the first matching item in the array?
First of all you have a syntax error.
$array=$array(['f'=>'foo', 'f'=>'foo', 'f'=>'foo','g'=>'good']);
You have an $ extra and [] extras, and you can't have a lots off records with the same key(because the last one will override the previously)... The correct way to define
$array= array('f'=> array('foo', 'foo2', 'foo3'), 'g'=>'good');
The values will be a new array inside de F key. And then you can remove only one record
unset($array['f'][0]);
now your arrays var_dump:
$array= array('f'=> array('foo2', 'foo3'), 'g'=>'good');
i have solved this by using this as per cmorrissy comment there will be only one item so that variable was showing me qty, i have to check if
if($product[$id]['quantity']>1){ $product[$id]['quantity']--;}else{unset($product[$id]);}
if you var_dump($array); this would be the output
var_dump($array);
array(
f => foo
g => good
)
since you have an array with the same index it will be displayed as one, and thats why it will be deleted

Check if element exists in PHP array

I have an array which is given below:
array(1) { [0]=> array(1) { ["type"]=> string(4) "item" } }
I'm using to the following code in an if statement to see if "item" exists in the array but it isn't been evaluated as true
if (array_key_exists('item', $_SESSION['type']))
{
//do something
}
What am I doing wrong?
array_key_exists checks the keys of the array, not the values; "item" is a value.
To check for the existence of values use either in_array (if you don't care about the key in case the item is found) or array_search (if you want to know what the key for that item was). For example:
if (in_array("item", $_SESSION['type'])) // do something
Its array in array. And function array_key_exists checks only one level deep, if the key exists. And your ked is 2 levels deep, so it cant return true, because there is key only "0".
And "item" is not key, but value; you have to use function in_array or array_search.
And also you should create your own function for that, because its array in array...
You need to use in_array to find if an element exists in an array.
array_key_exists checks if the key of the array is present or not

Fast method for Looping through Array to match a common ID in a second array

I'm trying to systematically loop through 2 arrays, and match their values for some quick processing. Let me set up my specific situation:
Array 1
productID,
companyID,
name,
price
Array 2
companyID,
name,
rebate1,
rebate2
I want to loop through Array 1, and when the companyID matches an ID inside of Array 2, I will do some quick math based on the rebate1, rebate2 values for that companyID.
Right now I am looping through Array 1, and then on EACH item in Array 1 I loop through the entire Array 2 to see if the companyID exists. I know this can't be the fastest/cleanest solution...
EDIT
The key values for Array 1 look like:
$array1[0]['productID']
$array1[0]['companyID'] (etc...)
$array1[1]['productID']
$array1[1]['companyID'] (etc...)
The key values for Array 2 look like:
$array2[0]['companyID']
$array2[0]['rebate1'] (etc...)
$array2[1]['companyID']
$array2[1]['rebate1'] (etc...)
Use the companyId as key for Array 2, i.e., make sure that
$Array2[$Array1[$i]['companyID']]['companyID'] == $Array1[$i]['companyID']
This gives you constant time lookup of companies in Array 2 based on companyID and you can do your calculation with
$Array2[$Array1[$i]['companyID']]['rebate1']`
and
$Array2[$Array1[$i]['companyID']]['rebate2']`
Example:
foreach ($Array1 as $value) {
if (isset($Array2[$value['companyID']])) {
//TODO: use $Array2[$value['companyID']] for calculation
} else {
// TODO: handle case companyID not in $Array2
}
}
What approximate sizes do you expect for each of your arrays?
While as you say, your method isn't certainly the fastest (looks like 0(n²)), below 10'000 elements in each array I doubt you can see any significant speed difference.
If you have 150'000 in array1 and 200'000 in array2, that's a whole other story and you'll have to look for an algorithm that is rather 0(log n).
Edit:
As mentioned above, let's just make your array associative if you can:
Instead of:
Array2 = array(
0 => array(
'Company_id' => 'Hello',
'rebate_1' => '50%',
)
);
Make it:
Array2 = array(
'Hello' => array(
'rebate_1' => '50%',
)
);
And then use:
if (isset(array2[$company_id]))
{
// do your stuff
}
If you can't modify Array2's structure where it's coming from, you should transform it on the fly in your search function's scope, so that it looks like above, and then use the transformed array. Transforming Array2 into an associative one shouldn't take too long, for the number of elements you say you have.
The easiest way I can think of is to use the companyID as the key for Array 2:
$companies[$companyID]=array($name,$rebate1,$rebate2)
and then you just reference it directly looping Array 1
$products[$x]=array($productID,$companyID,$name,$price);
...
$newprice1=$products[$x][3]/$companies[$products[$x][1]][1];
$newprice2=$products[$x][3]/$companies[$products[$x][1]][2];
My answer is slightly different from the first one, mind the arrays...
You can create a new array indexed by the company id as follows:
$cid = array_map(function($a) {return $a['companyID'];}, $array2);
$new2 = array_combine($cid, $array2);
With that, you can loop through the first array and access the data:
foreach ($array1 as $key => $value){
$rebate1 = $new2[$value['companyID']]['rebate1'];
$rebate2 = $new2[$value['companyID']]['rebate2'];
}

Categories