PHP Loop - Sum the Value of an Array if the Key Exists - php

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);

Related

PHP Arrays looping and creating multi dimensional arrays

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);

PHP: merge multidimensional, associative arrays (LEFT JOIN simulation - keep duplicates, keep non-existent elements)

I got two associative, multidimensional arrays $arrayOffered and $arraySold. I would like to merge them under certain conditions:
if value of key 'item' from $arrayOffered exists in $arraySold, both elements should be included in array $result. If for 1 element from $arrayOffered there are 3 elements in $arraySold, I should get also 3 elements in $result.
otherwise, element from $arrayOffered should be added into $result.
One element from $arrayOffered can have >1 equivalents in $arraySold. They should be joined in the way shown below.
Input data:
$arrayOffered = array(
0 => array('item' => 'product_1', 'Category' => 'ABC'),
1 => array('item' => 'product_2', 'Category' => 'DEF')
);
$arraySold = array(
0 => array('item' => 'product_1', 'ItemsSold' => '2', 'ItemsReturned' => 1), //arrays in this array can contain up to 30 elements
1 => array('item' => 'product_1', 'ItemsSold' => '1')
);
Desired result:
$desiredResult = array(
0 => array('item' => 'product_1', 'Category' => 'ABC', 'ItemsSold' => '2', 'ItemsReturned' => 1),
1 => array('item' => 'product_1', 'Category' => 'ABC', 'ItemsSold' => '1'),
2 => array('item' => 'product_2', 'Category' => 'DEF')
);
I got stuck on something like:
$result = array();
foreach ($arrayOffered as $keyOffered => $offeredSubArr)
{
$item = $offeredSubArr['item'];
foreach($arraySold as $keySold => $soldSubArr)
{
if(isset($soldSubArr['item']) && $soldSubArr['item'] == $item)
{
$i = 0;
$test = array_merge($offeredSubArr, $soldSubArr);
$result[$i][] = $test;
$i++;
}
else
{
$result[$i][] = $offeredSubArr;
$i++;
}
}
}
Problem:
- output array isn't formatted the way I wanted
- I know I'm not going in the right direction. Can you please give me a hint?
This is an option, since you have this $arrayOffered as a kind of master file I suggest to build a hash with this array and use later on the foreach look for sold array.
$arrayOffered = array(
0 => array('item' => 'product_1', 'Category' => 'ABC'),
1 => array('item' => 'product_2', 'Category' => 'DEF')
);
$arraySold = array(
0 => array('item' => 'product_1', 'ItemsSold' => '2', 'ItemsReturned' => 1), //arrays in this array can contain up to 30 elements
1 => array('item' => 'product_1', 'ItemsSold' => '1')
);
//Build a hash to get the extra properties
$hashArray = array();
foreach ($arrayOffered as $offered) {
$hashArray[$offered['item']]=$offered;
}
$resultArray = array();
foreach ($arraySold as $sold) {
$hashItem = $hashArray[$sold['item']];
// you dont want this sold flag on your final result
unset($hashItem['sold']);
$resultArray[]=array_merge($hashItem,$sold);
$hashArray[$sold['item']]['sold']= true;
}
//Add all the missing hash items
foreach($hashArray as $hashItem){
if(!isset($hashItem['sold'])){
$resultArray[]=$hashItem;
}
}
print_r($resultArray);
Test sample
http://sandbox.onlinephpfunctions.com/code/f48ceb3deb328088209fbaef4f01d8d4430478db
$result = array();
foreach ($arrayOffered as $keyOffered => $offeredSubArr)
{
$item = $offeredSubArr['item'];
foreach($arraySold as $keySold => $soldSubArr)
{ $i = 0;
if(isset($soldSubArr['item']) && $soldSubArr['item'] == $item)
{
$test = array_merge($offeredSubArr, $soldSubArr);
$result[$i][] = $test;
}
else
{
$result[$i][] = $offeredSubArr;
}
$i++;
}
}
$result = $result[0];
echo '<pre>'; print_r($result); die();
Well i will try to follow your logic although there is simpler solutions.
First of all we will need to search in a multidimentional array thats why we will need the followed function from this so thread
function in_array_r($needle, $haystack, $strict = false) {
foreach ($haystack as $item) {
if (($strict ? $item === $needle : $item == $needle) || (is_array($item) && in_array_r($needle, $item, $strict))) {
return true;
}
}
return false;
}
Next after small changes:
$i you don't need to make it zero on every loop just once so place it outside
unnecessary [] ($result[$i][]) you don't need the empty brackets no reason to create an extra table in the $i row since what you add there, the $test is already table itself
Adding the last loop coz when sth is not in the second table it will be added in your new table in every loop and as far as i get you don't want that kind of duplicates
We have the following code:
$arrayOffered = array(
0 => array('item' => 'product_1', 'Category' => 'ABC'),
1 => array('item' => 'product_2', 'Category' => 'DEF')
);
$arraySold = array(
0 => array('item' => 'product_1', 'ItemsSold' => '2', 'ItemsReturned' => 1), //arrays in this array can contain up to 30 elements
1 => array('item' => 'product_1', 'ItemsSold' => '1')
);
$i = 0;
$result = array();
foreach ($arrayOffered as $keyOffered => $offeredSubArr)
{
$item = $offeredSubArr['item'];
foreach($arraySold as $keySold => $soldSubArr)
{
if(isset($soldSubArr['item']) && $soldSubArr['item'] == $item)
{
$test = array_merge($offeredSubArr, $soldSubArr);
$result[$i] = $test;
$i++;
}
}
}
foreach ($arrayOffered as $value)
{
if (!in_array_r($value['item'], $result))
{
$result[$i] = $value;
$i++;
}
}
print_r($result);
Which as far as i tested gives the wanted result.

Multidimensional array looping (PHP) - a better way?

Is there a better/more efficient way to loop through this data?
I need to loop through the array data with the 'Name' first and the 'ListID' second but the external API request generates the array as per the code below (the other way round).
// Array Data
$csList = array(
array(
'ListID' => 'BGERFwQTrHoseE4sweebqwyAxuJ9YU',
'Name' => 'Monthly Newsletter Subscribers'
),
array(
'ListID' => 'kHdUQMbELgMyojuATz9Dsbxz3WViVo',
'Name' => 'Special Mailout'
)
);
// Generate Array Varaibles
foreach($csList as $array => $values) {
foreach($values as $k => $v) {
for($i = 1; $i < count($csList); $i++) {
$csListData[$k][] = $v;
}
}
}
// Loop Data
for($i = 0; $i < count($csList); $i++) {
echo $csListData['Name'][$i].'<br>';
echo $csListData['ListID'][$i].'<br>';
}
It's not at all clear why you're rearranging the data. Loop over the array and access whatever keys you want in whatever order you want.
$csList = array(
array(
'ListID' => 'BGERFwQTrHoseE4sweebqwyAxuJ9YU',
'Name' => 'Monthly Newsletter Subscribers'
),
array(
'ListID' => 'kHdUQMbELgMyojuATz9Dsbxz3WViVo',
'Name' => 'Special Mailout'
)
);
foreach ($csList as $item) {
echo $item['Name'].'<br>';
echo $item['ListID'].'<br>';
}
Your inner for loop is useless. You can use the $array key to get your array as wanted :
foreach($csList as $array => $values) {
foreach($values as $k => $v) {
$csListData[$k][$array] = $v;
}
}
// Loop Data
for($i = 0, $c = count($csList); $i <$c; $i++) {
echo '<br>';
echo $csListData['Name'][$i].'<br>';
echo $csListData['ListID'][$i].'<br>';
}
Also, moving the count() out of the check will avoid to count at every iteration of the loop.
// Array Data
$csList = array(
array(
'ListID' => 'BGERFwQTrHoseE4sweebqwyAxuJ9YU',
'Name' => 'Monthly Newsletter Subscribers'
),
array(
'ListID' => 'kHdUQMbELgMyojuATz9Dsbxz3WViVo',
'Name' => 'Special Mailout'
)
);
You can do as follow:
$newCsList = array();
$newCsList = array_map(function ($val){
return array_reverse($val,true);
},$csList);
The result is like:
**Array (
[0] => Array (
[Name] => Monthly Newsletter Subscribers
[ListID] => BGERFwQTrHoseE4sweebqwyAxuJ9YU
)
[1] => Array (
[Name] => Special Mailout
[ListID] => kHdUQMbELgMyojuATz9Dsbxz3WViVo
)
)**
But for taking each element you can do:
$newCsList = array();
$newCsList = array_map(function ($val){
$my_test_ary = array_reverse($val);
echo $my_test_ary['Name'].'<br/>'.$my_test_ary['ListId'];
},$csList);

Given this array, how can I reformat it to look like this

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

How to filter this php array

I have an array:
Array(
[0] => Array(
['title'] => 'Apple',
['type'] => '1'
),
[1] => Array(
['title'] => 'Oranage',
['type'] => '2'
),
[2] => Array(
['title'] => 'Tomato',
['type'] => '1'
),
//when compares with [0], 'type' is equal and both contains 'Apple', remove.
[3] => Array(
['title'] => 'Red Apple',
['type'] => '1'
),
[4] => Array(
['title'] => 'Big Tomato',
['type'] => '3'
),
//when compares with [1], 'type' is equal and both contains 'Oranage', remove.
[5] => Array(
['title'] => 'Sweet Oranage',
['type'] => '2'
)
);
If the 'type' element is equal, while 'title' elment contains the same string ([0] and [3] contains 'Apple'), then only one element will be used.
The result will be:
Array(
[0] => Array(
['title'] => 'Apple',
['type'] => '1'
),
[1] => Array(
['title'] => 'Oranage',
['type'] => '2'
),
[2] => Array(
['title'] => 'Tomato',
['type'] => '1'
),
[4] => Array(
['title'] => 'Big Tomato',
['type'] => '3'
)
);
How to filter this, I am so confused.
Thanks.
If you consider your conditions as alternative, then if passing one of the following criteria, only one of all the values meeting specific criteria can be used:
the 'type' element is equal,
the 'title' element in each second level array are the same ([2] and [5]), or
one 'title' element contains another([0] and [3]),
If so, you can just use some indexing arrays for storing already found 'type' and 'title' variables and:
add one variable,
check whether the next variable:
has 'type' already in the index table,
has 'title' already in the index,
is contained in 'title' already defined in index or contains 'title' already defined in index,
if 2. shows that at least one of the criteria is met, do not add it to the result, otherwise add it,
go to point 2.
In the return you should receive what you described. Just write it in PHP.
Something like this should do:
$array = array(/* your array */);
$filteredArray = array();
foreach ($array as $key => $elem) {
foreach ($filteredArray as $comp) {
if ($elem['type'] == $comp['type'] &&
(strpos($elem['title'], $comp['title']) !== false || strpos($comp['title'], $elem['title']) !== false)
) {
continue 2; // skip to the next $elem
}
}
$filteredArray[$key] = $elem;
}
If the array is held in variable $ar, then:
$filtered = Array();
for(int $i = 0; $i < count($ar); $i++) {
for(int $j = $i; $j < count($ar); $j++) {
if($ar[$i][$type] == $ar[$i][$type]) {
if(strlen($ar[$i][$title]) < strlen($ar[$j][$title])) {
$larger = $j;
$smaller = $i;
}
else {
$larger = $i;
$smaller = $j;
}
if(preg_match(strtolower($smaller), strtolower($larger)) {
$filtered = array_merge($filtered, array_slice($ar, 0, $larger - 1), array_slice($ar, $larger, count($ar) - $larger));
}
}
}
}
Finds two elements with equal types. Then, take the title of the element with the shortest title, and search through the other element for a preg_match. If found, merge the previous filtered array with all of the elements before and after the duplicate.

Categories