I have a shopping cart with three items like this:
$cart = [
1031 => [
'id' => '1031',
'model' => 'tr16',
'price' => 100,
'discount_applied' => '',
'promo_name' => '',
'promo_id' => ''
],
1032 => [
'id' => '1032',
'model' => 'tr16g',
'price' => 100,
'discount_applied' => '',
'promo_name' => '',
'promo_id' => ''
],
1034 => [
'id' => '1034',
'model' => 'tr17g',
'price' => 100,
'discount_applied' => '',
'promo_name' => '',
'promo_id' => ''
]
];
I have an array of IDs representing items eligible for a discount like this:
$itemIds = [
0 => [
0 => 1031
],
1 => [
0 => 1032
]
];
I loop thru each array and change the price where the ID in $cart matches ID in $itemIds by applying a 20% discount, and also add new elements. That code looks like this:
foreach($cart as &$item) {
foreach($itemIds as $ids) {
foreach($ids as $key => $value) {
if ($item['id'] == $value)
{
$item['discount_applied'] = $item['price'] * 0.2;
$item['price'] = $item['price'] * .80;
$item['promo_name'] = 'Test promo';
$item['promo_id'] = 36;
}
}
}
}
Printing the cart to the screen before and after the loop shows it's working as expected.
However, I encounter a problem when trying to loop through the modified $cart and calculate the sum of individual discounts.
My loop looks like this:
$cart['total_discount'] = 0;
foreach($cart as $item)
{
$cart['total_discount'] += $item['discount_applied'];
}
echo 'Total discount:' . $cart['total_discount'];
I expect to see the sum of discounts = 40, but instead = 60. Printing the cart to the screen before and after the loop shows that items 1031 and 1032 have a value of 20 in discount_applied and that item 1034 has no value.
Any help in identifying where I have an error or errors is appreciated.
Here's all the code if you want to copy/paste.
$cart = [
1031 => [
'id' => '1031',
'model' => 'tr16',
'price' => 100,
'discount_applied' => '',
'promo_name' => '',
'promo_id' => ''
],
1032 => [
'id' => '1032',
'model' => 'tr16g',
'price' => 100,
'discount_applied' => '',
'promo_name' => '',
'promo_id' => ''
],
1034 => [
'id' => '1034',
'model' => 'tr17g',
'price' => 100,
'discount_applied' => '',
'promo_name' => '',
'promo_id' => ''
]
];
$itemIds = [
0 => [
0 => 1031
],
1 => [
0 => 1032
]
];
echo '<h2>Cart BEFORE discount</h2>'; echo '<pre>';print_r($cart); echo '</pre>';
foreach($cart as &$item) {
foreach($itemIds as $ids) {
foreach($ids as $key => $value) {
if ($item['id'] == $value)
{
$item['discount_applied'] = $item['price'] * 0.2);
$item['price'] = $item['price'] * .80;
$item['promo_name'] = 'Test promo';
$item['promo_id'] = 36;
}
}
}
}
echo '<h2>Cart AFTER discount</h2>'; echo '<pre>';print_r($cart); echo '</pre>';
$cart['total_discount'] = 0;
foreach($cart as $item)
{
echo $item['discount_applied'] . '<br>';
$cart['total_discount'] += $item['discount_applied'];
}
echo 'Total discount:' . $cart['total_discount'];
Your use of &$item in the initial loop needs to be used in your final loop also. The loop where you adding up the discount total. You will also need to see if the discount value is a number since, in the code you posted, the 3rd item in the cart will have a blank value for the discount which will throw a non-numeric error when trying to add it to the discount total.
Your final loop modified to work:
$cart['total_discount'] = 0;
foreach($cart as &$item) {
echo '*' . $item['discount_applied'] . '*<br />'; // just to show what is or isn't there
$cart['total_discount'] += (is_numeric($item['discount_applied']) ? $item['discount_applied'] : 0);
}
echo 'Total discount:' . $cart['total_discount'];
Related
how can i show php array multiplying in loop
I have to show in the foreach so that I can add mysql
$data = [
[
"id" => "3202",
"total" => "5"
],[
"id" => "3190",
"total" => "2"
],[
"id" => "3199",
"total" => "5"
]
];
foreach($data as $v){
//$v["total"]*
//output = 5x2x5= 50
}
You can use array_column and array_product in this problem:
<?php
$data = [
['id' => '3202','total' => '5'],
['id' => '3190','total' => '2'],
['id' => '3199','total' => '5']
];
$total = array_column($data, 'total');
$product = array_product($total);
printf('The product of total: %s', $product);
PHP array functions online
<?php
$data = [
['id' => '3202','total' => '5'],
['id' => '3190','total' => '2'],
['id' => '3199','total' => '5']
];
$total = 1; // empty product
$output = [];
foreach($data as $v) {
$total *= $v['total'];
$output[] = $v['total'];
}
echo implode('x', $output) . '= ' . $total; // 5x2x5= 50
Might want to also add logic to check if the $data is empty first with count($data), then when the list is empty, output a message instead.
I need to add new elemets to my array when a new category value is encountered. When a category value is encountered after the first time, its value1 and value2 values should be added to the first encounter's respective values.
Also, in the result array, I no longer wish to keep the category column. The category-grouping rows should use the category value as its name value.
Sample input:
$datas = [
[
'category' => 'Solution',
'name' => 'Name1',
'value1' => 20,
'value2' => 21
],
[
'category' => 'Solution',
'name' => 'Name2',
'value1' => 30,
'value2' => 31
],
[
'category' => 'Solution1',
'name' => 'Name3',
'value1' => 40,
'value2' => 41
]
];
Desired result:
[
['name' => 'Solution', 'value1' => 50, 'value2' => 52],
['name' => 'Name1', 'value1' => 20, 'value2' => 21],
['name' => 'Name2', 'value1' => 30, 'value2' => 31],
['name' => 'Solution1', 'value1' => 40, 'value2' => 41],
['name' => 'Name3', 'value1' => 40, 'value2' => 41]
]
I tried like this:
private function groupByProductSuperCategory($datas)
{
$return = [];
foreach ($datas as $data) {
$return[$data['category']][$data['name']] = array_sum(array_column('category', $data);
}
return $return;
}
The idea is to calculate first all sum values for by category, and after that just put values from name like another array. Have you an idea of how to do that?
From the posted array... To end in the desired array, there is some tiny fixes to do first. But I assumed it was due to typos while copying here...
So here is the array I started with:
$result = [
0 => [
"category" => 'Solution',
"name" => 'Name1',
"value1" => 20,
"value2" => 21
],
1 => [
"category" => 'Solution',
"name" => 'Name2',
"value1" => 30,
"value2" => 31
],
2 => [
"category" => 'Solution1',
"name" => 'Name3',
"value1" => 40,
"value2" => 41
]
];
Now, that re-organization of the data is a bit more complex than it looks... You need to perform several loops to:
Find distinct "category" names
Perform the summations for each
Add the sum item and the single items
So here is the code I ended with:
function groupByProductSuperCategory($datas){
$category = [];
$return = [];
// Find distinct categories
foreach ($datas as $data) {
if(!in_array($data["category"],$category)){
array_push($category,$data["category"]);
}
}
// For each distinct category, add the sum item and the single items
foreach ($category as $cat) {
// Get the sums
if(!in_array($cat,$return)){
$sum1 = 0;
$sum2 = 0;
foreach ($datas as $data) {
if($data["category"] == $cat){
$sum1 += $data["value1"];
$sum2 += $data["value2"];
}
}
}
// Push the sums in the return array
array_push($return,[
"name" => $cat,
"value1" => $sum1,
"value2" => $sum2,
]);
// Push the single elements
foreach ($datas as $data) {
if($cat == $data["category"]){
array_push($return,[
"name" => $data["name"],
"value1" => $data["value1"],
"value2" => $data["value2"],
]);
}
}
}
return $return;
}
Here is a PHPFiddle to try it out... Hit [F9] to run.
It is much more direct, efficient, and readable to implement a single loop and push reference variables into the result array to allow summing based on shared categories without keeping track of the actual indexes of the category rows.
Code: (Demo)
$result = [];
foreach ($array as $row) {
if (!isset($ref[$row['category']])) {
$ref[$row['category']] = [
'name' => $row['category'],
'value1' => 0,
'value2' => 0
];
$result[] = &$ref[$row['category']];
}
$ref[$row['category']]['value1'] += $row['value1'];
$ref[$row['category']]['value2'] += $row['value2'];
unset($row['category']);
$result[] = $row;
}
var_export($result);
I have function in class, which returns array with 4 3-4 rows. I have to use each value from related row in table values. I can print builded function atrray, and can print on parent file, but can not get values for elements for each row. Here is my class file:
<?php
class Anyclass
{
public function $monthly($array)
{
.
.
.
}
public function myfunction($array)
{
foreach ($ShowMonths as $duration) {
$array['Credit']['downpayment'] = 0;
$array['Credit']['duration'] = $duration;
$monthly = $this->monthly($array);
$Table['Options'][] = array(
'downpayment' => $array['Credit']['downpayment'],
'duration' => $array['Credit']['duration'],
'monthly' => $monthly,
'total' => $monthly * $array['Credit']['duration'] + $array['Credit']['downpayment']
);
}
print_r($Table);
}
}
Here is my main file
include_once('mypathtofile/FileWithClass.php');
$Cll = new NewOne();
$array = array(
'Rule' => array(
'rule_id' => 1,
'rule_name' => 'Mobile phones',
'interest' => 0.01,
'comission' => 0.01,
'best_offer_downpayment' => 0.5,
'best_offer_duration' => 6
),
'Product' => array(
'product_id' => 1,
'category_id' => 1,
'manufacturer_id' => 1,
'product_price' => 500
),
'Credit' => array(
'downpayment' => 100,
'duration' => 6
)
);
$prtst = $Cll->myfunction($array);
How can I call each elemet for each row?
I'm not sure what you are trying to do, but if you need to get each value in a multidimensional array - you can use recursion:
function get_value($array){
foreach($array as $item){
if(is_array($item)){
get_value($item);
} else {
echo $item;
}
}
}
For example I have an array like:
$items = [
'0' => [
'name' => 'item1',
'percent' => 10
],
'2' => [
'name' => 'item2',
'percent' => 20
],
'3' => [
'name' => 'item3',
'percent' => 30
],
'4' => [
'name' => 'item4',
'percent' => 40
],
];
And function:
function echoRandomItem(){
}
If I call this function it should return 'name' of the item depending on the 'percent' value. Basically if I call this function 100 times it should return item1 10 times, item2 20 times, item3 30 times, item4 40 times.
Here is a solution I've come up with thanks to Oliver's hint. $items is a given array. wrand() function is responsible for random weighted distribution calculation.
$items = [
'1' => [
'name' => 'item1',
'rand' => 10
],
'2' => [
'name' => 'item2',
'rand' => 20
],
'3' => [
'name' => 'item3',
'rand' => 30
],
'4' => [
'name' => 'item4',
'rand' => 40
],
];
function wrand($data) {
foreach ($data as $value) {
$itemsRand[] = $value ['rand'];
}
$totalw = array_sum($itemsRand);
$rand = rand(1, $totalw);
$curw = 0;
foreach ($data as $val) {
$curw += $val['rand'];
if ($curw >= $rand) return $val['name'];
}
return end($data);
}
Further code simply calls wrand() function 100 times and counts the results.
static $item1 = 0;
static $item2 = 0;
static $item3 = 0;
static $item4 = 0;
for ($i = 0; $i < 100; $i++){
$k = wrand($items);
if ($k == 'item1') {
$item1++;
} elseif ($k == 'item2'){
$item2++;
} elseif ($k == 'item3'){
$item3++;
} elseif ($k == 'item4'){
$item4++;
}
}
echo "item1 = $item1<br>";
echo "item2 = $item2<br>";
echo "item3 = $item3<br>";
echo "item4 = $item4";
This data comes from a POST form, the idea is to simply add more lines whenever a new product is added.
The current output is:
l. Banana 3 units: 150
Please take a look into the script (specially the foreach loop):
<?php
session_start();
//Getting the list
$list= $_SESSION['list'];
//stock
$products = array(
'Pineaple' => 500, 'Banana' => 50, 'Mango' => 150,
'Milk' => 500, 'Coffe' => 1200, 'Butter' => 300,
'Bread' => 450, 'Juice' => 780, 'Peanuts' => 800,
'Yogurt' => 450, 'Beer' => 550, 'Wine' => 2500,
);
//Saving the stuff
$_SESSION['list'] = array(
'item' => ($_POST['product']),
'quantity' => ($_POST['quantity']),
'code' => ($_POST['code']),
);
//price
$price = $products[($_SESSION['list']['item'])] * $_SESSION['list']['quantity'];
$_SESSION['list']['price'] = $price;
//listing
echo "<b>SHOPPIGN LIST</b></br>";
foreach($_SESSION as $key => $item)
{
echo $key[''], '. ', $item['item'], ' ', $item['quantity'], ' units: ', $item['price'];
}
//Recycling list
$_SESSION['list'] = $list;
echo "</br> <a href='index.html'>Return to index</a> </br>";
//Printing session
var_dump($_SESSION);
?>
change this code:
//Saving the stuff
$_SESSION['list'] = array(
'item' => ($_POST['product']),
'quantity' => ($_POST['quantity']),
'code' => ($_POST['code']),
);
to
//Saving the stuff
$_SESSION['list'][] = array(
'item' => ($_POST['product']),
'quantity' => ($_POST['quantity']),
'code' => ($_POST['code']),
);
and remove this code:
//Recycling list
$_SESSION['list'] = $list;
Now, you'll get a new entry in $_SESSION every time you POST to the page.
Also, if you want your output to look like:
l. Banana 3 units: 150
2. Orange 5 units: 250
etc
then you'll need to change the echo in the foreach() loop from
echo $key[''] . // everything else
to just
echo ($key+1) . // everything else
Since key will be your array index starting at 0, you'll need to do a +1 every iteration, otherwise your list would look like
0. Banana 3 units: 150
1. Orange 5 units: 250
As iandouglas wrote, you are overwriting the session variable every time. The following code also fixes some undefined index issues and already existing products.
// Test POST data.
$_POST['product'] = 'Pineaple';
$_POST['quantity'] = 1;
$_POST['code'] = 1;
//Getting the list
$_SESSION['list'] = isset($_SESSION['list']) ? $_SESSION['list'] : array();
//stock
$products = array(
'Pineaple' => 500, 'Banana' => 50, 'Mango' => 150,
'Milk' => 500, 'Coffe' => 1200, 'Butter' => 300,
'Bread' => 450, 'Juice' => 780, 'Peanuts' => 800,
'Yogurt' => 450, 'Beer' => 550, 'Wine' => 2500,
);
//Saving the stuff
$new_item = array(
'item' => $_POST['product'],
'quantity' => $_POST['quantity'],
'code' => $_POST['code'],
'price' => $products[$_POST['product']] * $_POST['quantity'],
);
$new_product = true;
foreach($_SESSION['list'] as $key => $item) {
if ($item['item'] == $new_item['item']) {
$_SESSION['list'][$key]['quantity'] += $new_item['quantity'];
$_SESSION['list'][$key]['price'] = $products[$new_item['item']] * $new_item['quantity'];
$new_product = false;
}
}
if ($new_product) {
$_SESSION['list'][] = $new_item;
}
//listing
echo "<b>SHOPPIGN LIST</b></br>";
foreach($_SESSION['list'] as $key => $item) {
echo 'key '. $key. ' '. $item['item'], ' ', $item['quantity'], ' units: ', $item['price']. '<br />';
}