Group and Calculate Values in Array - php

I have an array like the following:
Array
(
[0] => Array
(
[0] => Array
(
[Product_Name] => Apple Pie - 8"
[Product_Qty] => 1
[Product_Cat] => Pies
)
[1] => Array
(
[Product_Name] => Pecan Pie - 8"
[Product_Qty] => 1
[Product_Cat] => Pies
)
)
[1] => Array
(
[0] => Array
(
[Product_Name] => Apple Pie - 8"
[Product_Qty] => 1
[Product_Cat] => Pies
)
)
[2] => Array
(
[0] => Array
(
[Product_Name] => Strawberry Pie - 8"
[Product_Qty] => 1
[Product_Cat] => Pies
)
[1] => Array
(
[Product_Name] => Pecan Pie - 8"
[Product_Qty] => 1
[Product_Cat] => Pies
)
)
[3] => Array
(
[0] => Array
(
[Product_Name] => Lemon Pie - 8"
[Product_Qty] => 1
[Product_Cat] => Pies
)
[1] => Array
(
[Product_Name] => Pecan Pie - 8"
[Product_Qty] => 1
[Product_Cat] => Pies
)
)
)
I'm trying to group by same Product_Name and also add up the Product_Qty in each. Any help is greatly appreciated.

You can create a double loop and sum all value of every different product under a different array key as below:
$myArr = [
0 => [
0 => [
"Product_Name" => "Apple Pie - 8",
"Product_Qty" => 1,
"Product_Cat" => "Pies"
],
1 => [
"Product_Name" => "Apple Pie - 8",
"Product_Qty" => 1,
"Product_Cat" => "Pies"
]
],
1 => [
0 => [
"Product_Name" => "Pecan Pie - 8",
"Product_Qty" => 1,
"Product_Cat" => "Pies"
]
],
2 => [
0 => [
"Product_Name" => "Strawberry Pie - 8",
"Product_Qty" => 1,
"Product_Cat" => "Pies"
],
1 => [
"Product_Name" => "Pecan Pie - 8",
"Product_Qty" => 1,
"Product_Cat" => "Pies"
]
],
3 => [
0 => [
"Product_Name" => "Lemon Pie - 8",
"Product_Qty" => 1,
"Product_Cat" => "Pies"
],
1 => [
"Product_Name" => "Pecan Pie - 8",
"Product_Qty" => 1,
"Product_Cat" => "Pies"
]
]
];
$total = [];
foreach($myArr as $group){
foreach($group as $item){
$total[$item["Product_Name"]] = isset($total[$item["Product_Name"]]) ? $total[$item["Product_Name"]] + $item["Product_Qty"] : $item["Product_Qty"];
}
}
var_dump($total);
It will provide that total:
array(4) {
["Apple Pie - 8"]=>
int(2)
["Pecan Pie - 8"]=>
int(3)
["Strawberry Pie - 8"]=>
int(1)
["Lemon Pie - 8"]=>
int(1)
}

If you want to get all data as in array now then you can run below code.
$finalArray = array();
$product_name_arr = array();
foreach ($array as $key => $value) {
foreach ($value as $sub_key => $sub_value) {
if(in_array($sub_value['Product_Name'], $product_name_arr)){
foreach ($finalArray as $fa_key => $fa_value) {
if($fa_value['Product_Name'] == $sub_value['Product_Name']){
$finalArray[$fa_key]['Product_Qty'] = $finalArray[$fa_key]['Product_Qty'] + $sub_value['Product_Qty'];
}
}
} else {
$product_name_arr[] = $sub_value['Product_Name'];
$finalArray[] = $sub_value;
}
}
}

Related

PHP : Add lowest value from duplicate records of array

I want to remove duplicate record which is highest value in array.
Array :
Array
(
[0] => Array
(
[id] => 1
[number] => 123
[price] => 6
)
[1] => Array
(
[id] => 2
[number] => 456
[price] => 6
)
[2] => Array
(
[id] => 3
[number] => 123
[price] => 5
)
)
Expected Result :
Array
(
[0] => Array
(
[id] => 2
[number] => 456
[price] => 6
)
[1] => Array
(
[id] => 3
[number] => 123
[price] => 5
)
)
number is duplicate field and after that need to compare price. Which will be lower that will be display. Rest of all should be removed.
What I tried :
$lowest = min($myArray);
$result = array_filter($myArray, function($value, $key) use ($lowest) {
return $value === $lowest;
}, ARRAY_FILTER_USE_BOTH);
How can i do that?
UPDATE :
#Daniel Dez solution is almost working. I used 3rd solution of him. But, It should be working like this.
For ex : number 123 is duplicate records now it's lowest price is 2. Then, it should be display rest of 123 number's array element remove.
Array :
$data = [
[
"id" => 1,
"number" => 123,
"price" => 2,
],
[
"id" => 2,
"number" => 456,
"price" => 6,
],
[
"id" => 3,
"number" => 123,
"price" => 5,
],
[
"id" => 4,
"number" => 123,
"price" => 11,
],
[
"id" => 5,
"number" => 456,
"price" => 5,
],
[
"id" => 6,
"number" => 123,
"price" => 5,
]
];
Expected Output :
Array
(
[0] => Array
(
[id] => 1
[number] => 123
[price] => 2
)
[1] => Array
(
[id] => 2
[number] => 456
[price] => 5
)
)
please help me.
Thanks.
Data:
$numbers = array_unique(array_column($data, 'number'));
usort($data, function ($a, $b) {
return $a['price'] - $b['price'];
});
$result = [];
foreach ($numbers as $number) {
foreach ($data as $item) {
if ($item['number'] == $number) {
break;
}
}
$result[] = $item;
}
print_r($result);

How to get certain values from multidimensional arrays?

Here's the data I am working with right now:
$city = [
[
"name" => "Dhaka",
"areas" => ["d1", "d2", "d3"]
],
[
"name" => "Chittagong",
"areas" => ["c1", "c2", "c3"]
],
[
"name" => "Sylhet",
"areas" => ["s1", "s2", "s3"]
],
[
"name" => "Barisal",
"areas" => ["b1", "b2", "b3"]
],
[
"name" => "Khulna",
"areas" => ["k1", "k2", "k3"]
],
[
"name" => "Rajshahi",
"areas" => ["r1", "r2", "r3"]
],
];
I would like to get a list of data associated with only "name" key.
I would also like to show the data associated with "area" key once the user go for the corresponding "name".
It would be helpful if there were any suggestion on how to better store this data for frequent usage in code.
As long as the names are unique you can do this simple trick:
Example 1
$city = [
[
"name" => "Dhaka",
"areas" => ["d1", "d2", "d3"]
],
[
"name" => "Chittagong",
"areas" => ["c1", "c2", "c3"]
],
[
"name" => "Sylhet",
"areas" => ["s1", "s2", "s3"]
],
[
"name" => "Barisal",
"areas" => ["b1", "b2", "b3"]
],
[
"name" => "Khulna",
"areas" => ["k1", "k2", "k3"]
],
[
"name" => "Rajshahi",
"areas" => ["r1", "r2", "r3"]
],
];
$names = array_column($city, null, 'name');
print_r($names);
Output
Array
(
[Dhaka] => Array
(
[name] => Dhaka
[areas] => Array
(
[0] => d1
[1] => d2
[2] => d3
)
)
[Chittagong] => Array
(
[name] => Chittagong
[areas] => Array
(
[0] => c1
[1] => c2
[2] => c3
)
)
[Sylhet] => Array
(
[name] => Sylhet
[areas] => Array
(
[0] => s1
[1] => s2
[2] => s3
)
)
[Barisal] => Array
(
[name] => Barisal
[areas] => Array
(
[0] => b1
[1] => b2
[2] => b3
)
)
[Khulna] => Array
(
[name] => Khulna
[areas] => Array
(
[0] => k1
[1] => k2
[2] => k3
)
)
[Rajshahi] => Array
(
[name] => Rajshahi
[areas] => Array
(
[0] => r1
[1] => r2
[2] => r3
)
)
)
Now you can lookup by name
print_r($city['Chittagong']['areas']); //["c1", "c2", "c3"]
If the names are not guaranteed to be unique, you'll have to build them using foreach, like this:
Example 2
$city = [
[
"name" => "Dhaka",
"areas" => ["d1", "d2", "d3"]
],
[
"name" => "Chittagong",
"areas" => ["c1", "c2", "c3"]
],
[ /*--- ADDED to show duplication ---- */
"name" => "Chittagong",
"areas" => ["x1", "x2", "x3"]
],
[
"name" => "Sylhet",
"areas" => ["s1", "s2", "s3"]
],
[
"name" => "Barisal",
"areas" => ["b1", "b2", "b3"]
],
[
"name" => "Khulna",
"areas" => ["k1", "k2", "k3"]
],
[
"name" => "Rajshahi",
"areas" => ["r1", "r2", "r3"]
],
];
$output = [];
foreach($city as $k=>$v){
$k = $v['name'];
if(!isset($output[$k])) $output[$k] = []; //initialize
$output[$k][] = $v;
}
print_r($output);
Which will give you something like this:
Array
(
[Dhaka] => Array
(
[0] => Array
(
[name] => Dhaka
[areas] => Array
(
[0] => d1
[1] => d2
[2] => d3
)
)
)
[Chittagong] => Array
(
[0] => Array
(
[name] => Chittagong
[areas] => Array
(
[0] => c1
[1] => c2
[2] => c3
)
)
[1] => Array
(
[name] => Chittagong
[areas] => Array
(
[0] => x1
[1] => x2
[2] => x3
)
)
)
[Sylhet] => Array( ... )
As you can see this adds an extra level in to contain the multiple occurrences. Of course you could just combine the area when duplicate (in the foreach). But that is up to you.
Here is a quick example of that (same data as above):
Example 3
$output = [];
foreach($city as $k=>$v){
$k = $v['name'];
if(!isset($output[$k])) $output[$k] = []; //initialize
$output[$k] = array_merge($output[$k], $v['areas']); //merge the areas
}
print_r($output);
Output
Array
(
[Dhaka] => Array
(
[0] => d1
[1] => d2
[2] => d3
)
[Chittagong] => Array
(
[0] => c1
[1] => c2
[2] => c3
[3] => x1
[4] => x2
[5] => x3
)
....
)
If it was me, I would go with the last one, just because of the simplicity it will have working with it later.
PS. if your pulling data out of a Database with PDO, you can use $stmt->fetchAll(PDO::FETCH_GROUP) which will give you something like the second example automatically. The only caveat here is that the name column is the first one selected in the Query, which is the column it will group on.
Cheers.
If you're just trying to loop through the list of cities and get the names you can just use a foreach loop. If you need something beyond this try to define your question a little more.
foreach ($city as $c) {
echo $c["name"];
}

group mysql results in multidimensional array

I have the following:
$variants = [
0 => [
"variant_name" => "iPhone 5",
"sku_id" => "2",
"sku" => "GLC-IPH5REDXXXL",
"stock_total" => "10",
"stock_left" => "10",
"retail_price" => 1000,
"on_sale_price" => 0
],
1 => [
"variant_name" => "Red",
"sku_id" => "2",
"sku" => "GLC-IPH5REDXXXL",
"stock_total" => "10",
"stock_left" => "10",
"retail_price" => 1000,
"on_sale_price" => 0
],
2 => [
"variant_name" => "iPhone 6s Plus",
"sku_id" => "4",
"sku" => "GLC-IPH6SP",
"stock_total" => "5",
"stock_left" => "5",
"retail_price" => 1000,
"on_sale_price" => 0
],
3 => [
"variant_name" => "iPhone 6s",
"sku_id" => "13",
"sku" => "GLC-IPH6S",
"stock_total" => "5",
"stock_left" => "5",
"retail_price" => 1000,
"on_sale_price" => 0
]
]
I would like to put them in the following array
0 => [
"sku_id" => "2",
"sku" => "GLC-IPH5REDXXXL",
"stock_total" => "10",
"stock_left" => "10",
"retail_price" => 1000,
"on_sale_price" => 0,
"options" => ['iPhone 4', 'Red'],
"option1" => 'iPhone4',
"option2" => 'Red',
"option3" => null
],
1 => [
"sku_id" => "4",
"sku" => "GLC-IPH6SP",
"stock_total" => "5",
"stock_left" => "5",
"retail_price" => 1000,
"on_sale_price" => 0,
"options" => ['iPhone 6s Plus'],
"option1" => 'iPhone 6s Plus',
"option2" => null,
"option3" => null
],
2 => [
"sku_id" => "13",
"sku" => "GLC-IPH6S",
"stock_total" => "5",
"stock_left" => "5",
"retail_price" => 1000,
"on_sale_price" => 0,
"options" => ['iPhone 6s'],
"option1" => 'iPhone 6s',
"option2" => null,
"option3" => null
]
I can't fill the options with each variant_name
I can't set the option1, option2, option3 with each corresponding variant_name
I've tried a simple foreach($variants as $v) loop on the first array and I got it working until options, option1, option2, option3 from which I get the repeating values.
I just can't figure it out how to do it, any suggestions?
You could use a simple foreach() and perhaps a for(). The for() here is a little inefficient because it runs every time, so it's highly repetitive and continually overwrites...but it works:
foreach($variants as $rows) {
$sku[$rows['sku_id']]['sku_id'] = $rows['sku_id'];
$sku[$rows['sku_id']]['sku'] = $rows['sku'];
$sku[$rows['sku_id']]['stock_total'] = $rows['stock_total'];
$sku[$rows['sku_id']]['stock_left'] = $rows['stock_left'];
$sku[$rows['sku_id']]['retail_price'] = $rows['retail_price'];
$sku[$rows['sku_id']]['on_sale_price'] = $rows['on_sale_price'];
$sku[$rows['sku_id']]['options'][] = $rows['variant_name'];
for($i = 0; $i < 3; $i++)
$sku[$rows['sku_id']]['option'.($i+1)] = (isset($sku[$rows['sku_id']]['options'][$i]))? $sku[$rows['sku_id']]['options'][$i] : NULL;
}
echo print_r(array_values($sku));
Gives you:
Array
(
[0] => Array
(
[sku] => GLC-IPH5REDXXXL
[stock_total] => 10
[stock_left] => 10
[retail_price] => 1000
[on_sale_price] => 0
[options] => Array
(
[0] => iPhone 5
[1] => Red
)
[option1] => iPhone 5
[option2] => Red
[option3] =>
)
[1] => Array
(
[sku] => GLC-IPH6SP
[stock_total] => 5
[stock_left] => 5
[retail_price] => 1000
[on_sale_price] => 0
[options] => Array
(
[0] => iPhone 6s Plus
)
[option1] => iPhone 6s Plus
[option2] =>
[option3] =>
)
[2] => Array
(
[sku] => GLC-IPH6S
[stock_total] => 5
[stock_left] => 5
[retail_price] => 1000
[on_sale_price] => 0
[options] => Array
(
[0] => iPhone 6s
)
[option1] => iPhone 6s
[option2] =>
[option3] =>
)
)
Solution
$result = [];
foreach($variants as $v) {
$result[$v['sku_id']]['sku_id'] = $v['sku_id'];
$result[$v['sku_id']]['sku'] = $v['sku'];
$result[$v['sku_id']]['stock_left'] = $v['stock_left'];
$result[$v['sku_id']]['retail_price'] = price($v['retail_price']);
$result[$v['sku_id']]['options'][] = $v['variant_name'];
if(isset($result[$v['sku_id']]['options'][0])) {
$result[$v['sku_id']]['option1'] = $result[$v['sku_id']]['options'][0];
}
else {
$result[$v['sku_id']]['option1'] = null;
}
if(isset($result[$v['sku_id']]['options'][1])) {
$result[$v['sku_id']]['option2'] = $result[$v['sku_id']]['options'][1];
}
else {
$result[$v['sku_id']]['option2'] = null;
}
if(isset($result[$v['sku_id']]['options'][2])) {
$result[$v['sku_id']]['option3'] = $result[$v['sku_id']]['options'][2];
}
else {
$result[$v['sku_id']]['option3'] = null;
}
}
return $result;

Creating Array Key Name with Dynamic Array

I am trying to get the example below to have key names for each dimension so it would look more like this:
Array
(
[Mobile] => Array
(
[0] => Array
(
[product_id] => 007
[product_name] => Blackberry R-900 Mobile
[product_price] => £450
[product_status] => 1
[product_category] => Mobile
)
Instead of the example below,
I have included the class that I am using to create the array into a categorized array and the usage of it.
The function appendNode in array2arraytree is where the algorithm actually creates the new array for each category.
Thanks for any help.
Example:
Array
(
[0] => Array
(
[0] => Array
(
[product_id] => 007
[product_name] => Blackberry R-900 Mobile
[product_price] => £450
[product_status] => 1
[product_category] => Mobile
)
[1] => Array
(
[product_id] => 001
[product_name] => Wespro Multi-SIM & Touch-screen Mobile
[product_price] => £150
[product_status] => 1
[product_category] => Mobile
)
[2] => Array
(
[product_id] => 004
[product_name] => Sigmatel MP4/MP3 + Camera Mobile
[product_price] => £150
[product_status] => 1
[product_category] => Mobile
)
)
[1] => Array
(
[0] => Array
(
[product_id] => 033
[product_name] => 8 GB Pendrive
[product_price] => £14.99
[product_status] => 0
[product_category] => Computers
)
[1] => Array
(
[product_id] => 334
[product_name] => 250 GB Portable Hard Drive
[product_price] => £79.99
[product_status] => 1
[product_category] => Computers
)
)
[2] => Array
(
[0] => Array
(
[product_id] => 033
[product_name] => The White Tiger – Aravind Adiga
[product_price] => £29.99
[product_status] => 1
[product_category] => Books
)
[1] => Array
(
[product_id] => 4501
[product_name] => The Final Reckoning - Sam Bourne
[product_price] => £19.99
[product_status] => 0
[product_category] => Books
)
[2] => Array
(
[product_id] => 034
[product_name] => The Final Reckoning - Sam Bourne
[product_price] => £15.79
[product_status] => 0
[product_category] => Books
)
)
)
Usage:
<?php
require_once("array2arraytree.php");
$arrProducts=array(
array(
"product_id" => "007",
"product_name" => "Blackberry R-900 Mobile",
"product_price" => "£450",
"product_status" =>"1",
"product_category" =>"Mobile"
),
array(
"product_id" => "033",
"product_name" => "8 GB Pendrive",
"product_price" => "£14.99",
"product_status" => "0",
"product_category" => "Computers"
),
array(
"product_id" => "033",
"product_name" => "The White Tiger – Aravind Adiga",
"product_price" => "£29.99",
"product_status" => "1",
"product_category" => "Books"
),
array(
"product_id" => "4501",
"product_name" => "The Final Reckoning - Sam Bourne",
"product_price" => "£19.99",
"product_status" => "0",
"product_category" => "Books"
),
array(
"product_id" => "001",
"product_name" => "Wespro Multi-SIM & Touch-screen Mobile",
"product_price" => "£150",
"product_status" => "1",
"product_category" => "Mobile"
),
array(
"product_id" => "004",
"product_name" => "Sigmatel MP4/MP3 + Camera Mobile",
"product_price" => "£150",
"product_status" => "1",
"product_category" => "Mobile"
),
array(
"product_id" => "034",
"product_name" => "The Final Reckoning - Sam Bourne",
"product_price" => "£15.79",
"product_status" => "0",
"product_category" => "Books"
),
array(
"product_id" => "334",
"product_name" => "250 GB Portable Hard Drive",
"product_price" => "£79.99",
"product_status" => "1",
"product_category" => "Computers"
)
);
$objTree=new Array2ArrayTree($arrProducts,"product_category");
$arrTree=$objTree->makeTree();
print("<pre>");
print_r($arrTree);
print("</pre>");
?>
Class Array2ArrayTree:
class Array2ArrayTree
{
public $arrOriginal = array();
public $arrDummy = array();
public $strKey = "";
public function __construct($arrData, $arrKey)
{
$this->arrOriginal = $arrData;
$this->strKey = $arrKey;
$this->arrDummy = array();
}
public function makeTree()
{
for ($i = 0; $i <= sizeof($this->arrOriginal) - 1; $i++) {
$keyPosition = $this->searchKey($this->arrOriginal[$i][$this->strKey]);
if ($keyPosition == -1) {
$this->addNode($this->arrOriginal[$i]);
} else {
$this->appendNode($this->arrOriginal[$i], $keyPosition);
}
}
return $this->arrDummy;
}
function searchKey($strCurrentValue)
{
for ($i = 0; $i <= sizeof($this->arrDummy) - 1; $i++) {
if ($this->arrDummy[$i][0][$this->strKey] == $strCurrentValue) {
return $i;
}
}
return - 1;
}
function addNode($arrNode)
{
$this->arrDummy[sizeof($this->arrDummy)][0] = $arrNode;
}
function appendNode($arrNode, $keyPosition)
{
array_push($this->arrDummy[$keyPosition], $arrNode);
}
}
?>
Should be even simpler:
public function makeTree()
{
foreach($this->arrOriginal as $value) {
$this->arrDummy[$value[$this->strKey]][] = $value;
}
return $this->arrDummy;
}
I think this would work - map the array to get the keys you want, then use array_filter to get only the items in that category:
//get the keys you want:
$keys = array_unique(array_map(function($item) { return $item['product_category']; }, $array));
$return = [];
foreach($keys as $key) {
//filter the array to the one's in the current category, and reindex them to 0:
$return[$key] = array_values(array_filter($array, function($item) use ($key) {
return $item['product_category'] == $key;
}));
}

How to loop through a multi-layer array and replace some associate values in it?

How can I loop through a multi-layer array and replace some associate values in it?
For instance, this is my array,
$items = array(
0 => array(
"id" => "1",
"title" => "parent 1",
"children" => array()
),
1 => array(
"id" => "2",
"title" => "parent 2",
"children" => array (
0 => array(
"id" => "4",
"title" => "children 1",
"granchildren" => array(
0 => array(
"id" => "7",
"title" => "granchildren 1"
),
1 => array(
"id" => "8",
"title" => "granchildren 2"
)
)
),
1 => array(
"id" => "5",
"title" => "children 2",
"granchildren" => array()
)
),
),
3 => array(
"id" => "3",
"title" => "parent 3",
"children" => array()
)
);
These are two working functions I have,
function translate ($id){
$items = array(
0 => array(
"id" => 1,
"title" => "parent 1 en"
),
1 => array(
"id" => 4,
"title" => "children 1 en"
),
2 => array(
"id" => 8,
"title" => "granchildren 2 en"
)
);
foreach($items as $item) {
if($id === $item['id'])
{
return $item['title'];
}
}
}
function looper ($items){
$new_items = array();
foreach($items as $key => $item) {
if(isset($key) && is_array($key)){
$new_items[$key] = translate($item['id']);
}else {
//looper($item);
}
}
return $new_items;
}
print_r(looper ($items));
This is the result I am after,
Array
(
[0] => Array
(
[id] => 1
[title] => parent 1 en // translated
[children] => Array
(
)
)
[1] => Array
(
[id] => 2
[title] => parent 2
[children] => Array
(
[0] => Array
(
[id] => 4
[title] => children 1 en // translated
[granchildren] => Array
(
[0] => Array
(
[id] => 7
[title] => granchildren 1
)
[1] => Array
(
[id] => 8
[title] => granchildren 2 en // translated
)
)
)
[1] => Array
(
[id] => 5
[title] => children 2
[granchildren] => Array
(
)
)
)
)
[3] => Array
(
[id] => 3
[title] => parent 3
[children] => Array
(
)
)
)
Is it possible?
Sounds like a job for array_walk or array_walk_recursive.
It will call a user-supplied function for every item in an array. You can have it modify the array by reference to achieve what you're after.

Categories