Compare two multidimensional arrays in PHP to sum datas - php

I've two arrays:
Array A:
$rates = array(
'apple' = array(
'red' => 1.19,
'green' => 0.99,
'yellow' => 0.89
)
);
Array B:
$cart = array(
'apple' = array(
'0' => red,
'1' => green
)
);
The array B is the cart one and I need to get rates from Array A.
So:
Apple > red > 1.19
Apple > green > 0.99
Total should be 2.18.
This is what I tried:
foreach($cart as $key => $arr){
if(!in_array($key[$arr], $rates)){
$total += $rates[$key];
}
}
But it doesn't work.
What I'm missing please ?
Thanks a lot for any help.

You have a couple of problems. Firstly, you should be checking whether the product type from $cart exists as a key in $rates i.e.
if(!in_array($key[$arr], $rates)){
should be:
if (isset($rates[$key])) {
Secondly, once you have determined that the key does exist in $rates you then need to iterate over each of the values in $arr to get their price from $rates (using the null coalescing operator to avoid problems with values not being in the rates array):
$total = 0;
foreach ($cart as $key => $arr) {
if (isset($rates[$key])) {
foreach ($arr as $value) {
$total += $rates[$key][$value] ?? 0;
}
}
}
echo $total;
Output:
2.18
Demo on 3v4l.org

<?php
$rates = array(
'apple' => array(
'red' => 1.19,
'green' => 0.99,
'yellow' => 0.89
)
);
$cart = array(
'apple' => array(
'0' => 'red',
'1' => 'green'
)
);
$total = 0;
foreach($cart as $type => $items) {
if(array_key_exists($type, $rates)) {
foreach($items as $item) {
if(array_key_exists($item, $rates[$type])) {
$total += $rates[$type][$item];
}
}
}
}
echo $total;
?>

Related

calcultion based on items minus stock value php

I have a calcultion based on items minus stock value (with some community help). If it hits zero then the next row will be touched.
$items = 45;
$stockRows = [40, 50, 60];
$newStock = function ($items, $stock) {
foreach ($stock as &$item) {
$delta = $item - $items;
$item = $delta > 0 ? $delta : 0;
$items = $delta < 0 ? abs($delta) : 0;
}
return $stock;
};
print_r($newStock($items, $stockRows));
Output
Array
(
[0] => 0
[1] => 45
[2] => 60
)
Now I want to add a row identifier so that I can update the database rows afterwards in a foreach and set the correct stock amount
$stockRows =
array(
array(
'id' => 1,
'amount' => 30
),
array(
'id' => 2,
'amount' => 40
),
array(
'id' => 3,
'amount' => 50
)
);
I cant get this to work. And if I get a output the first array result returns id 0.
Fixed it myself
$items = 45;
$ids = [1, 2, 3];
$stockRows = [40, 50, 60];
$newStock = function ($afschrijving, $stock, $ids) {
$i = 0;
foreach ($stock as &$item) {
$delta = $item - $afschrijving;
$item = array($id[$i++], $delta > 0 ? $delta : 0);
$afschrijving = $delta < 0 ? abs($delta) : 0;
}
return $stock;
};
print_r($newStock($items, $stockRows, $ids));

How to count the number of item in foreach loop based by it's parent?

I have a simple loop to display a list. But I do not know how to count it's parent item. This is my current attempt:
$no = 0;
$ct = 0;
$type = "";
foreach($item as $row_item){
$no = $no + 1;
if($type != $row_item['type']){
$ct = $ct + 1;
}
echo $no." ".$row_item['type']." ".$row_item['item'];
$type = $row_item['type'];
}
My desired output :
1 TYPE_A 3 A1
2 TYPE_A 3 A2
3 TYPE_A 3 A3
4 TYPE_B 2 B1
5 TYPE_B 2 B2
In order to count the total number of each type you'll need to iterate over the entire collection twice. Once to count the totals, and once to display the results for each row. The code below actually does 3 loops, the array_filter method iterates over the entire array, but I like the clean code. :)
http://sandbox.onlinephpfunctions.com/code/962f418715d1518c818732f6e59ba4f28d5a19f3
<?php
$items = array(
array( 'name' => 'A1', 'type' => 'TYPE_A' ),
array( 'name' => 'A2', 'type' => 'TYPE_A' ),
array( 'name' => 'A3', 'type' => 'TYPE_A' ),
array( 'name' => 'B1', 'type' => 'TYPE_B' ),
array( 'name' => 'B2', 'type' => 'TYPE_B' )
);
function is_TYPE_A( $item ) {
return $item['type'] == 'TYPE_A';
}
function is_TYPE_B( $item ) {
return $item['type'] == 'TYPE_B';
}
$TYPE_A_COUNT = count( array_filter( $items, 'is_TYPE_A' ) );
$TYPE_B_COUNT = count( array_filter( $items, 'is_TYPE_B' ) );
function getTypeTotalByItem( $item ) {
global $TYPE_A_COUNT, $TYPE_B_COUNT;
if ( $item['type'] == 'TYPE_A' ) {
return $TYPE_A_COUNT;
}
if ( $item['type'] == 'TYPE_B' ) {
return $TYPE_B_COUNT;
}
}
for ( $i = 0; $i < count( $items ); $i++ ) {
echo ( $i + 1 )." ".$items[$i]['type']." ".getTypeTotalByItem($items[$i])." ".$items[$i]['name']."\n";
}
You can use array_map() and a couple foreach() loops for this if you were so inclined. It should interpret fairly quickly:
# Create a storage array
$counter = [];
# Sort the main array into type
array_map(function($v) use (&$counter){
# Store the subs under the type
$counter[$v['type']][] = $v['item'];
},$items);
# Start counter
$i = 1;
# Loop through each type
foreach($counter as $title => $row){
# Count how many are under this type
$count = count($row);
# Loop the rows in the types arrays
foreach($row as $item) {
# Write increment, type, total count, item
echo $i." ".$title." ".$count." ".$item.'<br />';
$i++;
}
}

Find the position of a key in a multidimensional array in PHP

I have this array:
$actualPlan = 'medium';
$plans = array(
array(
'plans' => array(
'tiny' => 29,
'small' => 69,
'medium' => 179,
'big' => 359
)
)
);
During a foreach, I display the contents of plans of this array like this:
foreach($plans as $key => $data) {
foreach($data['plans'] as $plan => $rate) {
...
}
}
But how can I know the position of the $actualPlan ?
For example, for :
if $actualPlan == medium it should return me 3.
if $actualPlan == tiny it should return me 1.
Thanks.
inside the loop:
echo array_search($actualPlan, array_keys($rate)); // returns the index position as int
here will output 1,2,3,4 for the inputs 'tiny','small','medium','big'
Within the foreach($plans as $key => $data) {, you could make the conditional like this :
$current_plan = explode('___', $actualPlan);
$current_key = array_search($current_plan[0],array_keys($data['plans']));
foreach($data['plans'] as $plan => $rate) {
$current_iterated_key = array_search($plan,array_keys($data['plans']));
if ($current_iterated_key < $current_key) {
echo "$plan => Downgrade\r\n";
} elseif ($current_iterated_key > $current_key) {
echo "$plan => Upgrade\r\n";
} elseif($current_iterated_key == $current_key) {
echo "$plan => Current\r\n";
}
}

Aggregate arrays in multilevel array if their values match

I have an array in the following format:
array(5){
[0] =>
array(4){
['product-id'] => 8931
['product'] => 'Cake'
['description'] => 'Yellow cake'
['quantity'] => 1
}
[1] =>
array(4){
['product-id'] => 8921
['product'] => 'Cookies'
['description'] => 'Chocolate chip cookies'
['quantity'] => 2
}
[2] =>
array(4){
['product-id'] => 8931
['product'] => 'Cake'
['description'] => 'Yellow cake'
['quantity'] => 1
}
[3] =>
array(4){
['product-id'] => 8931
['product'] => 'Cake'
['description'] => 'Yellow cake'
['quantity'] => 4
}
[4] =>
array(4){
['product-id'] => 8933
['product'] => 'Cake'
['description'] => 'Chocolate cake'
['quantity'] => 1
}
}
How can I compare all the arrays to each other?
In my code I have sorted all the arrays by product ID, and written a for to compare two rows at a time, but now I see why that won't work.
function cmp($a, $b){
return strcmp($a[0], $b[0]);
}
function combineArrays($arrays){
usort($arrays, "cmp");
for($i = 1; $i < count($arrays); $i++){
$f_row = $arrays[$i];
$next = $i + 1;
$s_row = $arrays[$next];
if($f_row[0] == $s_row[0]){
if($f_row[1] == $s_row[1]){
if($f_row[2] == $s_row[2]){
$q1 = (int) $f_row[3];
$q2 = (int) $s_row[3];
$total = $q1 + $q2;
unset($f_row[3]);
$f_row[5] = $total;
unset($arrays[$next]);
}
}
}
}
return $arrays;
}
What is a better way to do this?
For example, to take the first array and compare it to the next, value for value. As soon as one of the first 3 values doesn't match, you go on to compare that row to the next one. If all of the first three values match, add up the quantity value of the two arrays, assign that to the first array's quantity, and get rid of the second array. There could be more matches, so continue comparing that array until you have gone through the whole list.
My favorite solution uses array_reduce():
$filtered = array_reduce(
// Reduce the original list
$arrays,
// The callback function adds $item to $carry (the partial result)
function (array $carry, array $item) {
// Generate a key that contains the first 3 properties
$key = $item['product-id'].'|'.$item['product'].'|'.$item['description'];
// Search into the partial list generated until now
if (array_key_exists($key, $carry)) {
// Update the existing item
$carry[$key]['quantity'] += $item['quantity'];
} else {
// Add the new item
$carry[$key] = $item;
}
// The array_reduce() callback must return the updated $carry
return $carry;
},
// Start with an empty list
array()
);
try this
$arr=array(
array(
'product-id' => 8931,
'product' => 'Cake',
'description' => 'Yellow cake',
'quantity' => 3,
),
array(
'product-id' => 8921,
'product' => 'Cookies',
'description' => 'Chocolate chip cookies',
'quantity' => 2,
),
array(
'product-id' => 8931,
'product' => 'Cake',
'description' => 'Yellow cake',
'quantity' => 1,
)
);
$id = array();
foreach ($arr as $key => $row)
{
$id[$key] = $row['product-id'];
}
array_multisort($id, SORT_DESC, $arr);
$result = array();
foreach ($arr as $key => $row)
{
$pid = $row['product-id'];
if(!isset($result[$pid]))
{
$result[$pid]=$row;
}else{
$result[$pid]['quantity']+=$row['quantity'];
}
}
print_r($result);
You are doing it the hard way, why not do it like this:
function combineProducts($products) {
$result = array();
foreach ($products as $product) {
//if you can have different product or descriptions
//per product id you can change this this to
//$productId = implode('|', array($product['product-id'], $product['product'], $product['description']);
$productId = $product['product-id'];
//check if we already have this product
if (isset($result[$productId])) {
//add to the quantity
$result[$productId]['quantity']+= $product['quantity'];
} else {
$result[$productId] = $product;
}
}
//sort the results (remove if not needed)
ksort($result);
//return values (change to return $result; if you want an assoc array)
return array_values($result);
}

Traverse multi dimensional array recursively without using foreach

I have an array like this and the code using foreach loop.
$arr = array( array ( array( 'CAR_TIR', 'Tires', 100 ),
array( 'CAR_OIL', 'Oil', 10 ),
array( 'CAR_SPK', 'Spark Plugs', 4 )
),
array ( array( 'VAN_TIR', 'Tires', 120 ),
array( 'VAN_OIL', 'Oil', 12 ),
array( 'VAN_SPK', 'Spark Plugs', 5 )
),
array ( array( 'TRK_TIR', 'Tires', 150 ),
array( 'TRK_OIL', 'Oil', 15 ),
array( 'TRK_SPK', 'Spark Plugs', 6 )
)
);
function recarray($array)
{
foreach($array as $key=>$value)
{
if(is_array($value))
{
RecArray($value);
}
else
{
echo "key = $key value = $value";
}
}
}
recarray($arr);
I have to traverse the array using recursion and without using foreach.
Simple depth first search:
function DFS($array) {
for ($i = 0; $i < count($array); $i ++) {
if (is_array($array[$i])) {
DFS($array[$i]);
}
else {
echo "key: ".$i.", value: ".$array[$i]."<br />";
}
}
}
What about array_walk_recursive()? it can apply function to each element of the array:
function test_print($value, $key)
{
echo "key = $key value = $value";
}
array_walk_recursive($arr, 'test_print');
not tested
I would use a while loop - like
while($i < count($array)) {}

Categories