I have an array of items listed bellow
array (
[0] => array(
'order' => 'order001',
'qty' => 90
),
[1] => array(
'order' => 'order002',
'qty' => 100
)
)
I also have a quantity(Q) that is to be fetched from the list above and the array have to be looped from top to bottom without even skipping a single item.
The loop will go through the first item to see if it can get the total requested and if the first loop cant meet the total then the it will return the total(T) got from the first item store it somewhere and then move to the next item in the array with a new value which lets say its (Q-T) and see if can find the quantity in the next item.
Now the problem is i cant actually figure out how to make hold and return the array as a list like in the case below.
Lets say i need a total of 120.
Array(
Array(
'order' => 'order001',
'qty' => 90
),
Array(
'order' => 'order002',
'qty' => 30
)
);
Maybe something like this?
https://iconoun.com/demo/temp_tonywiz.php
<?php // demo/temp_tonywiz.php
/**
* Working with arrays
*
* https://stackoverflow.com/questions/45264342/php-arrays-looping-and-creating-multi-dimensional-arrays
*/
error_reporting(E_ALL);
echo '<pre>';
$qty = 120;
$arr = [ ['order' => 'order001', 'qty' => 90], ['order' => 'order002', 'qty' => 100] ];
$out = [];
foreach ($arr as $sub)
{
if ($qty <= 0) break;
if ($sub['qty'] <= $qty)
{
$out[] = $sub;
$qty = $qty - $sub['qty'];
}
else
{
$sub['qty'] = $qty;
$out[] = $sub;
}
}
print_r($arr);
print_r($out);
Related
As an example I have two arrays:
Multidimensional Array 1:
$line_items = [
0 => ['price' => 41.99, 'id' => 12, 'quantity' => 1],
1 => ['price' => 155.95, 'id' => 11, 'quantity' => 1],
2 => ['price' => 21, 'id' => 13, 'quantity' => 1]
];
Regular Array 2:
$price_array = [
0 => 197.94,
1 => 21.00
];
And I want to add the prices of each array from Array 1 until they equal to the first element of Array 2.
At that point, I want to push the arrays from Array 1 that were used to sum that price into a new array, and repeat the process.
So for example the new array would look like this from the above arrays:
$finalArray = [
[
0 => [ "price" => 41.99, "id" => 12, "quantity" => 1 ],
1 => [ "price" => 155.95, "id" => 11, "quantity" => 1 ]
],[
0 => [ "price" => 21, "id" => 13, "quantity" => 1 ]
]
];
so far I have tried this:
$disposableTransactions_array = [];
foreach($lineitems_array as $lineitems){
//add the prices to the sum
$sum += $lineitems['price'];
//should the $sum reach the value of the first element in array
if($sum == $disposableTransactions_array[0]){
//push the $lineitems into a new array
$finalPrices_array[] = $lineitems;
//reset the sum
$sum = 0;
/* remove first element from checked array to allow the next element in array to be checked */
array_shift($disposableTransactions_array);
}
}
However, I am only getting this as output, rather than both arrays that were summed together being pushed into a multidimensional array:
$finalArray = [
0 => [ "price" => 155.95, "id" => 11, "quantity" => 1 ],
1 => [ "price" => 21, "id" => 13, "quantity" => 1 ]
];
I am a bit stuck on how to get my currently ouput array, into the array I desire.
I need to do this because I need to associate the different id's to the two different price points.
In my case the prices reflect transactions in an order, so line_items will appear in the same order as the price they are being compared against. The variable part is how many transactions are part of this order and how many line_items are present in a transaction.
So I believe the problem is within your foreach loop, specifically with the way you're identifying the items that need to be put into the array (you're only checking for the sum on the first value of your prices array at key $disposableTransactions_array[0]).
Since your arrays weren't attached to PHP variables*, I took some liberties in naming conventions but this code produces the output you're looking for:
$line_items = [
0 => ['price' => 41.99, 'id' => 12, 'quantity' => 1],
1 => ['price' => 155.95, 'id' => 11, 'quantity' => 1],
2 => ['price' => 21, 'id' => 13, 'quantity' => 1]
];
$price_array = [
0 => 197.94,
1 => 21.00
];
//$output_array stores our output
$output_array = [];
//$sum is used for our math, set a default value
$sum = 0;
//$sum_items are the items used to build the $output_array
$sum_items = [];
//loop through each $line_items
foreach($line_items as $arrayKey => $item){
//add the price of the current items to the sum
$sum += (float)$item['price'];
//add the current $line_items array key to $sum_items
$sum_items[] = $arrayKey;
//check to see if our current $sum is in $price_array
$key = array_search((float)$sum, $price_array);
if(false !== $key){
//we found the sum, clear out the $output_array_entry so we have a clean slate
$output_array_entry = [];
//loop through each item we used to get our current $sum
foreach($sum_items as $item_id){
//add each item in its entirety to the $output_array_entry from $line_items
$output_array_entry[] = $line_items[$item_id];
}
//add the $output_array_entry we just built to $output_array
$output_array[] = $output_array_entry;
//reset our variables
$sum_items = [];
$sum = 0;
}
}
var_dump($output_array);
The solution I'm proposing does three things different from the code you provided:
We use array_search instead of checking on $disposableTransactions_array[0] so we can account for multiple "sums" in the $price_array
We keep track of the array key from $line_items of the items we're adding together during the foreach loop in the form of $sum_items. We then use $sum_items to create our $output_array_entry which is all of the data from $line_items that we used to find the sum.
We save the data to $output_array
I will say though, this relies heavily on the way your $line_items array is structured. If we move any of those items to a different order, the addition may never find the correct $sum inside of $price_array and will return nothing. For Example, if our $line_items looks like this:
$line_items = [
0 => ['price' => 155.95, 'id' => 11, 'quantity' => 1],
1 => ['price' => 21, 'id' => 13, 'quantity' => 1],
2 => ['price' => 41.99, 'id' => 12, 'quantity' => 1],
];
The first time we loop through our $sum is 155.95, then on the next pass our $sum is 176.95, and then on the third pass $sum is 218.94 - none of which are in our $price_array. This makes me believe you may need another check - but without more context I'm not sure
Because the line items ALWAYS perfectly align with the order of the summed prices, the following approach is suitable/reliable.
Code: (Demo)
$bucket_sum = 0;
$bucket_index = 0;
$result = [];
foreach ($line_items as $row) {
$result[$bucket_index][] = $row;
$bucket_sum += $row['price'];
if ($bucket_sum >= $price_array[$bucket_index]) {
$bucket_sum = 0;
++$bucket_index;
}
}
var_export($result);
Keep pushing line items into the current element in the result array until its price total reach the defined sum in the price array. Then increment the index and reset the sum variable and proceed with pushing line items as described in the previous sentence.
As a personal challenge, I wanted to try to script a solution using reference variables. Demo
$result = [];
foreach ($line_items as $row) {
$lastKey = array_key_last($result);
if (
!$result
|| array_sum(array_column($result[$lastKey], 'price')) == $price_array[$lastKey]
) {
unset($ref);
$result[] = &$ref;
}
$ref[] = $row;
}
var_export($result);
And finally, a dense, functional-style approach: Demo
var_export(
array_reduce(
$line_items,
function($result, $row) use ($price_array) {
$index = (int) array_key_last($result);
$index += array_sum(array_column($result[$index] ?? [], 'price')) == $price_array[$index];
$result[$index][] = $row;
return $result;
},
[]
)
);
As you can see, there are many, many ways to attack this task. I didn't even mention consuming the price array while iterating ...I'll stop here.
I have got an array like this:
array (
0 =>
array (
'total_price' => '19.120000',
'total_percent' => '0.20',
'vat_code' => 22,
'discount_percent' => '3.82',
),
1 =>
array (
'total_price' => '58.000000',
'total_percent' => '0.60',
'vat_code' => 22,
'discount_percent' => '11.60',
),
2 =>
array (
'total_price' => '20.000000',
'total_percent' => '0.21',
'vat_code' => 4,
'discount_percent' => '4.00',
),
)
I'm trying to search values using 'vat_code' as key, and sum total_price, total_percent and discount_percent values if I find the same 'vat_code' value.
In other words, I wold like to obtain a result like this:
array (
0 =>
array (
'total_price' => '77.120000', // result of 58 + 19.12
'total_percent' => '0.80', // result of 0.60 + 0.20
'vat_code' => 22,
'discount_percent' => '15.42', // result of 11.60 + 3.82
),
1 =>
array (
'total_price' => '20.000000',
'total_percent' => '0.21',
'vat_code' => 4,
'discount_percent' => '4.00',
),
)
edit: here below the code I tried.
$rate_quantity_per_price = array();
$vat_code = intval($product_detail['tax_rate']);
$total_products = $order->total_products;
$discount_neat = $order->total_discounts_tax_excl; //
$quantity_row = $product_detail['product_quantity'];
$quantity_per_price = $product_detail['total_price_tax_excl'];
$row_total_price = $quantity_per_price / $total_products;
$item_row_total_percent = number_format($row_total_price, 2, '.', '');
$discount_splitted = $discount_neat * $row_total_price;
$row_discount_splitted = number_format($discount_splitted, 2, '.', '');
$row_product[] = array('total_price' => $quantity_per_price,
'total_percent' => $item_row_total_percent,
'vat_code' => $vat_code,
'discount_percent' => $row_discount_splitted);
if(!array_search($vat_code, $row_product)){
$rate_quantity_per_price[$vat_code] = $quantity_per_price;
$rate_total_price[$vat_code] = $item_row_total_percent;
$rate_discount_row[$vat_code] = $row_discount_splitted;
} else {
$rate_quantity_per_price[$vat_code] += $quantity_per_price;
$rate_total_price[$vat_code] += $item_row_total_percent;
$rate_discount_row[$vat_code] += $row_discount_splitted;
}
Thanks for all your support :-)
iterate using foreach loop
foreach($a as $v){
isset($group[$v['vat_code']]) ?
($group[$v['vat_code']]['total_price'] += $v['total_price'] AND
$group[$v['vat_code']]['total_percent'] += $v['total_percent'] AND
$group[$v['vat_code']]['discount_percent'] += $v['discount_percent']
)
:
($group[$v['vat_code']] = $v);
}
print_r(array_values($group));
Working example :- https://3v4l.org/Fp1hu
You have a single dimens array as input and output, therefore you will need at least one loop. Which loop type is up to you. You will need to initialize the output array before your loop starts to an empty array. Inside your loop you will need a conditional that tests the output array for the existence of the vat key of the current iterated record in the input array. That is your loop will need to iterate the input array. If the key is in the output array, then update that record's data in the output array; otherwise if it's not in the output array, add the record to the output array anew.
Pseudo code:
init output array
for records in input array:
if input record's vat is in output array then:
update output record
else
add record to output array
end for
At last I found the solution.
Here below the code:
$rate_products_array = array(); // output array
foreach($row_product as $n => $value) {
$vat_value = $value['vat_code'];
if(!array_key_exists($vat_value, $rate_products_array)) {
$rate_products_array[$vat_value]['total_price'] = $value['total_price'];
$rate_products_array[$vat_value]['total_percent'] = $value['total_percent'];
$rate_products_array[$vat_value]['discount_percent'] = $value['discount_percent'];
} else {
$rate_products_array[$vat_value]['total_price'] += $value['total_price'] ;
$rate_products_array[$vat_value]['total_percent'] += $value['total_percent'] ;
$rate_products_array[$vat_value]['discount_percent'] += $value['discount_percent'];
}
//$this->trace('rate products array :', $rate_products_array);
}
I have a multidimensional associative array that I need to loop through and collect the product specific data. Please see below:
$rawData = array(
array(
'sku' => 'product1',
'quantity' => '3'
),
array(
'sku' => 'product2',
'quantity' => '3'
),
array(
'sku' => 'product1',
'quantity' => '2'
)
);
$collectedData = array();
for ($i = 0; $i < count($rawData); $i++) {
$collectedData += array($rawData[$i]['sku'] => $rawData[$i]['quantity']);
}
print_r($collectedData);
This outputs the following:
Array
(
[product1] => 3
[product2] => 3
)
What I need however is that if the array key sku already exists in the $collectedData array, for the quantity of the array value to be added to the already existing quantity.
So this would be my desired result (as product1 exists twice with values 2 and 3):
Array
(
[product1] => 5
[product2] => 3
)
Is there an easy way of doing this? Thank you very much for any help in advance.
Simply check key is available or not. if avalable then sum quantity
$rawData = array(
array(
'sku' => 'product1',
'quantity' => '3'
),
array(
'sku' => 'product2',
'quantity' => '3'
),
array(
'sku' => 'product1',
'quantity' => '2'
)
);
$collectedData = array();
for ($i = 0; $i < count($rawData); $i++) {
if(isset($collectedData[$rawData[$i]['sku']]))
$collectedData[$rawData[$i]['sku']] += $rawData[$i]['quantity'];
else
$collectedData += array($rawData[$i]['sku'] => $rawData[$i]['quantity']);
}
print_r($collectedData);
Also I suggest you foreach loop for simplification and unneccessary use of indexes
$collectedData = array();
foreach($rawData as $row){
if(isset($collectedData[$row['sku']]))
$collectedData[$row['sku']] += $row['quantity'];
else
$collectedData += array($row['sku'] => $row['quantity']);
}
print_r($collectedData);
DEMO
Lop the array with foreach, and check if the key exists - if it doesn't, set the value to the quantity, if it does, add it to the existing quantity. The key represents the product. We check if its set or not to avoid having the code produce warnings (as you can see this demo produces).
$collectedData = array();
foreach ($rawData as $value) {
if (!isset($collectedData[$value['sku']]))
$collectedData[$value['sku']] = $value['quantity'];
else
$collectedData[$value['sku']] += $value['quantity'];
}
Live demo
$collectedData = array();
foreach($rawData as $data)
{
// if already exist then add
if(isset($collectedData[$data['sku']]))
{
$collectedData[$data['sku']] += $data['quantity'];
}
// else set value
else
{
$collectedData[$data['sku']] = $data['quantity'];
}
}
print_r($collectedData);
If I had an array:
$data = array(
array(
'manufacturers_id' => 29,
'manufacturers_name' => 'Quicksilver',
'products_quantity' => 1,
'products_price' => 15.6000,
'products_cost' => 8.0000,
),
array(
'manufacturers_id' => 29,
'manufacturers_name' => 'Quicksilver',
'products_quantity' => 2,
'products_price' => 4.6722,
'products_cost' => 2.4000,
)
);
How can I reformat this to provide the structure
Array
(
[Quiksilver] => Array
(
[brands_sales] => $brandsSalesVal
[brands_products_sold] => $brandsSoldVal
[brands_costs] => $brandsCostsVal
)
$brandsSalesVal = A sum of all the products_price * products_quantity (for each manufacturer_id)
$brandsSoldVal= A sum of all the products_quantity for each manufacturer
$brandsCostsVal= A sum of all the products_costs for each manufacturer
Any help is greatly appreciated and I am thankful for anyone to take time to answer my rather lengthy query. I am still getting to grips with reformating arrays.
You need to use a foreach loop like so:
// Declare the totals array and
// the manufacturers->id map
$totals = array();
$manufacturers = array();
// Loop through the array of products and populate
// the totals array
foreach($data as $value){
// Set the key to the manufacturers name
$key = $value['manufacturers_name'];
// If the array has not been built yet, then ensure the
// values are set to 0 and add the manufacturer to the
// manufacturers map if it is not already there
if(!isset($totals[$key])){
// Add the manufacturer to the map
$manufacturers[$value['manufacturers_id']] = $key;
// Default the values to 0
$totals[$key]['brand_sales'] = 0;
$totals[$key]['brands_products_sold'] = 0;
$totals[$key]['brands_costs'] = 0;
}
// Calculate the brand sales
$totals[$key]['brand_sales'] += ($value['products_price']*$value['products_quantity']);
// Calculate the brand sales
$totals[$key]['brands_products_sold'] += $value['products_quantity'];
// Calculate the brand sales
$totals[$key]['brands_costs'] += $value['products_cost'];
}
In order to access the information stored in the array generated above, you can use another foreach loop like so:
// Loop through the $totals array and print the result
foreach($totals as $key => $value){
// Print the manufacturers name and ID
echo "\n".$key." (ID: ".array_search($key,$manufacturers).")";
// Print the totals for the current manufacturer
echo "\n\tBrand Sales: ".$values['brand_sales'];
echo "\n\tBrand Products Sold: ".$values['brands_products_sold'];
echo "\n\tBrand Costs: ".$values['brands_costs'];
}
The array_search function is used to look up the ID of the manufacturer based on the manufacturers name stored in the $manufacturers array. You can alter the code so that it does not need the array_search function, but I have done it like this because traditionally you would map the ID->NAME, not NAME->ID. It is just personal preference...
For more information on the foreach loop, see here
$data = array(
array(
'manufacturers_id' => 29,
'manufacturers_name' => 'Quicksilver',
'products_quantity' => 1,
'products_price' => 15.6000,
'products_cost' => 8.0000,
),
array(
'manufacturers_id' => 29,
'manufacturers_name' => 'Quicksilver',
'products_quantity' => 2,
'products_price' => 4.6722,
'products_cost' => 2.4000,
)
,
array(
'manufacturers_id' => 30,
'manufacturers_name' => 'Different Brand',
'products_quantity' => 2,
'products_price' => 4.6722,
'products_cost' => 2.4000,
)
);
$sortedData = array();
foreach($data as $num => $row){
$manufacturersName = $row['manufacturers_name'];
//If we don't have an array made for the manufacturer yet, make one
if(!isset($sortedData[$manufacturersName])){
$sortedData[$manufacturersName] = array(
'brands_sales' => 0,
'brands_products_sold' => 0,
'brands_costs' => 0
);
};
//Make a reference to the relevant manufacturer sorted data
$manufacturerData = &$sortedData[$manufacturersName];
$qty = $row['products_quantity'];
//
$manufacturerData['brands_sales'] += $qty * $row['products_price'];
$manufacturerData['brands_products_sold'] += $qty;
$manufacturerData['brands_costs'] += $row['products_cost'];
}
var_dump($sortedData); // <- your result.
Result:
array (size=2)
'Quicksilver' =>
array (size=3)
'brands_sales' => float 24.9444
'brands_products_sold' => int 3
'brands_costs' => float 10.4
'Different Brand' =>
array (size=3)
'brands_sales' => float 9.3444
'brands_products_sold' => int 2
'brands_costs' => float 2.4
I have a multi-dimensional array that looks like this:
The base array is indexed based on category ids from my catalog.
$cat[category_id]
Each base array has three underlying elements:
['parent_id']
['sort_order']
['name']
I want to create a function that allows us to create a list of category_id's and names for a given parent_category_id in the correct sort order. Is this possible? Technically it is the same information, but the array is constructed in a weird way to extract that information.
Here is an example definition for the array:
$cat = array();
$cat[32]['parent_id']= 0;
$cat[32]['sort_order']= 1;
$cat[32]['name']= 'my-category-name1';
$cat[45]['parent_id']= 0;
$cat[45]['sort_order']= 0;
$cat[45]['name']= 'my-category-name2';
$cat[2]['parent_id']= 0;
$cat[2]['sort_order']= 2;
$cat[2]['name'] = "my-category-name3";
$cat[3]['parent_id']= 2;
$cat[3]['sort_order']= 1;
$cat[3]['name'] = "my-category-name4";
$cat[6]['parent_id']= 2;
$cat[6]['sort_order']= 0;
$cat[6]['name'] = "my-category-name5";
Assuming it's something of this sort:
$ary = Array(
0 => Array(
'parent_category_id' => null,
'sort_order' => 0,
'name' => 'my-category-name0'
),
1 => Array(
'parent_category_id' => 0,
'sort_order' => 1,
'name' => 'my-category-name1'
),
2 => Array(
'parent_category_id' => 0,
'sort_order' => 2,
'name' => 'my-category-name2'
),
3 => Array(
'parent_category_id' => null,
'sort_order' => 0,
'name' => 'my-category-name3'
),
4 => Array(
'parent_category_id' => 3,
'sort_order' => 0,
'name' => 'my-category-name4'
)
);
You can use a combination of a foreach and usort to achieve what you're going for.
// #array: the array you're searchign through
// #parent_id: the parent id you're filtering by
function getFromParent($array, $parent_id){
$result = Array();
foreach ($array as $category_id => $entry){
if ($entry['parent_category_id']===$parent_id)
$result[$category_id] = $entry;
}
usort($result,create_function('$a,$b','return ($a["sort_order"]>$b["sort_order"]?1:($b["sort_order"]<$a["sort_order"]?-1:0));'));
return $result;
}
var_export(getFromParent($ary,0));
EDIT Sorry, fixed some syntax errors. Tested, and works (at least to result in what I was intending)
EDITv2 Here's the raw output from the above:
array (
0 =>
array (
'parent_category_id' => 0,
'sort_order' => 1,
'name' => 'my-category-name1',
),
1 =>
array (
'parent_category_id' => 0,
'sort_order' => 2,
'name' => 'my-category-name2',
),
)
(Used var_export just for you #FelixKling)
EDITv3 I've updated my answer to go along with the OP's update. I also now make it retain the original "category_id" values in the result array.
First you create an empty array, it will be used to store your result.
$result = array();
You need to iterate through your initial array, you can use foreach().
Then, given your parent_category_id simply use an if statement to check whether it's the given id or not.
If it is, just construct and push your result to your $result array.
Use any of the sort functions you like
Use the magic return $result;
You're done.
function returnSortedParents($categories, $target_parent){
$new_list = array();
foreach($categories as $index => $array){
//FIND ONLY THE ELEMENTS MATCHING THE TARGET PARENT ID
if($array['parent_category_id']==$target_parent){
$new_list[$index = $array['sort_order'];
}
return asort($new_list); //SORT BASED ON THE VALUES, WHICH IS THE SORTING ORDER
}