Search duplicate value in array php and sum values - php

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

Related

How can I check and delete duplicate arrays?

how can I check and delete duplicate arrays?
Example:
$a = array(
array(
'id' => 1,
'name' => 'test'
),
// Next array is equal to first, then delete
array(
'id' => 1,
'name' => 'test'
),
// Different array, then continue here
array(
'id' => 2,
'name' => 'other'
)
);
If the array is the same, then delete the duplicate and get only one array.
You can use a lookup table storing serialized arrays. If an array already exists in the lookup table, you have a duplicate and can splice out the key:
$a = array(
array(
'id' => 1,
'name' => 'test'
),
array(
'id' => 1,
'name' => 'test'
),
array(
'id' => 2,
'name' => 'other'
)
);
$seen = [];
for ($i = count($a) - 1; $i >= 0; $i--) {
if (array_key_exists(json_encode($a[$i]), $seen)) {
array_splice($a, $i, 1);
}
else {
$seen[json_encode($a[$i])] = 1;
}
}
print_r($a);
Output:
Array
(
[0] => Array
(
[id] => 1
[name] => test
)
[1] => Array
(
[id] => 2
[name] => other
)
)
Try it!
array_unique()
Example:
$array = array(1, 2, 2, 3);
$array = array_unique($array); // Array is now (1, 2, 3)
You can loop through the parent array, serialize each child array and save it in a third array, and as you are looping, check for the existence of the serial of each next child array to all previous ones saved in the third array. If it exists, remove the current duplicate from the parent array by key. The function below demonstrates this.
function remove_duplicate_nested_arrays($parent_array)
$temporary_array = array(); // declare third, temporary array.
foreach($parent_array as $key => $child_array){ // loop through parent array
$child_array_serial = serialize($child_array); // serialize child each array
if(in_array($child_array_serial,$temporary_array)){ // check if child array serial exists in third array
unset($parent_array[$key]); // unset the child array by key from parent array if it's serial exists in third array
continue;
}
$temporary_array[] = $child_array_serial; // if this point is reached, the serial of child array is not in third array, so add it so duplicates can be detected in future iterations.
}
return $parent_array;
}
This can also be achieved in 1 line, using #Jose Carlos Gp suggestion as follows:
$b = array_map('unserialize', array_unique(array_map('serialize', $a)));
The function above kind of expands on what is actually happening in the 1 liner solution.

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

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 extract data out of a specific PHP array

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
}

Matching an array value by key in PHP

I have an array of items:
array(
[0] => array(
'item_no' => 1
'item_name' => 'foo
)
[1] => array(
'item_no' => 2
'item_name' => 'bar'
)
) etc. etc.
I am getting another array from a third party source and need to remove items that are not in my first array.
array(
[0] => array(
'item_no' => 1
)
[1] => array(
'item_no' => 100
) # should be removed as not in 1st array
How would I search the first array using each item in the second array like (in pseudo code):
if 'item_no' == x is in 1st array continue else remove it from 2nd array.
// Returns the item_no of an element
function get_item_no($arr) { return $arr['item_no']; }
// Arrays of the form "item_no => position in the array"
$myKeys = array_flip(array_map('get_item_no', $myArray));
$theirKeys = array_flip(array_map('get_item_no', $theirArray));
// the part of $theirKeys that has an item_no that's also in $myKeys
$validKeys = array_key_intersect($theirKeys, $myKeys);
// Array of the form "position in the array => item_no"
$validPos = array_flip($validKeys);
// The part of $theirArray that matches the positions in $validPos
$keptData = array_key_intersect($theirArray, $validPos);
// Reindex the remaining values from 0 to count() - 1
return array_values($keptData);
All of this would be easier if, instead of storing the key in the elements, you stored it as the array key (that is, you'd be using arrays of the form "item_no => item_data") :
// That's all there is to it
return array_key_intersect($theirArray, $myArray);
You can also do:
$my_array =array(
0 => array( 'item_no' => 1,'item_name' => 'foo'),
1 => array( 'item_no' => 2,'item_name' => 'bar')
);
$thrid_party_array = array(
0 => array( 'item_no' => 1),
1 => array( 'item_no' => 100),
);
$temp = array(); // create a temp array to hold just the item_no
foreach($my_array as $key => $val) {
$temp[] = $val['item_no'];
}
// now delete those entries which are not in temp array.
foreach($thrid_party_array as $key => $val) {
if(!in_array($val['item_no'],$temp)) {
unset($thrid_party_array[$key]);
}
}
Working link
If your key is not actually a key of your array but a value, you will probably need to do a linear search:
foreach ($itemsToRemove as $itemToRemove) {
foreach ($availableItems as $key => $availableItem) {
if ($itemToRemove['item_no'] === $availableItem['item_no']) {
unset($availableItems[$key]);
}
}
}
It would certainly be easier if item_no is also the key of the array items like:
$availableItems = array(
123 => array(
'item_no' => 123,
'item_name' => 'foo'
),
456 => array(
'item_no' => 456,
'item_name' => 'bar'
)
);
With this you could use a single foreach and delete the items by their keys:
foreach ($itemsToRemove as $itemToRemove) {
unset($availableItems[$itemToRemove['item_no']]);
}
You could use the following to build an mapping of item_no to your actual array keys:
$map = array();
foreach ($availableItems as $key => $availableItem) {
$map[$availableItems['item_no']] = $key;
}
Then you can use the following to use the mapping to delete the corresponding array item:
foreach ($itemsToRemove as $itemToRemove) {
unset($availableItems[$map[$itemToRemove['item_no']]]);
}

Categories