Merge arrays with Sum specific value keys - php

If someone has already done it, the idea is to merge different arrays into one and also merge the values sum of price, qty only for the identical keys.
In my example I only put two arrays to be merged $arr1, $arr2 but the idea is to do it dynamically because I do not have a defined number of arrays , I can have 2 as I can have 15.
Example:
<?php
$arr1 = [
51 => [
'name' => 'p1',
'price' => '20',
'qty' => '10',
'category' => 'c1'
],
3 => [
'name' => 'p2',
'price' => '10.50',
'qty' => '3',
'category' => 'c2'
]
];
$arr2 = [
3 => [
'name' => 'p3',
'price' => '23',
'qty' => '22',
'category' => 'c1'
],
102 => [
'name' => 'p4',
'price' => '10.50',
'qty' => '8',
'category' => 'c2'
]
];
Code :
mergeArrays(($arr1 + $arr2));
function mergeArrays($array)
{
$mergedArray = [];
foreach ($array as $k => $arr) {
foreach ($arr as $key => $value) {
if (!isset($mergedArray[$key])) {
$mergedArray[$k][$key] = $value;
} else {
$mergedArray[$key] += $value;
}
}
}
print_r($mergedArray);
//return $mergedArray;
}
Result:
Array
(
[51] => Array
(
[name] => p1
[price] => 20
[qty] => 10
[category] => c1
)
[3] => Array
(
[name] => p2
[price] => 10.50
[qty] => 3
[category] => c2
)
[102] => Array
(
[name] => p4
[price] => 10.50
[qty] => 8
[category] => c2
)
)
Expected result:
Array
(
[51] => Array
(
[name] => p1
[price] => 20
[qty] => 10
[category] => c1
)
[3] => Array
(
[name] => p3 // the last erray value
[price] => 33.50 //sum
[qty] => 25 //sum
[category] => c1 // the last erray value
)
[102] => Array
(
[name] => p4
[price] => 10.50
[qty] => 8
[category] => c2
)
)

Using the ...$in to indicate any number of arrays can be passed to the function and then a couple of loops will do the job for you
$arr1 = [ 51 => [ 'name' => 'p1', 'price' => '20', 'qty' => '10', 'category' => 'c1' ],
3 => [ 'name' => 'p2', 'price' => '10.50', 'qty' => '3', 'category' => 'c2' ]
];
$arr2 = [ 3 => [ 'name' => 'p3', 'price' => '23', 'qty' => '22', 'category' => 'c1' ],
102 => [ 'name' => 'p4', 'price' => '10.50', 'qty' => '8', 'category' => 'c2' ]
];
function myMerge(Array ...$in)
{
$new = $in[0];
for($i=1; $i<count($in); $i++){
foreach($in[$i] as $idx => &$a) {
if( isset($new[$idx]) ){
$new[$idx]['qty'] += $a['qty'];
$new[$idx]['price'] += $a['price'];
} else {
$new[$idx] = $a;
}
}
}
return $new;
}
print_r( myMerge($arr1, $arr2) );
RESULT
Array
(
[51] => Array
(
[name] => p1
[price] => 20
[qty] => 10
[category] => c1
)
[3] => Array
(
[name] => p2
[price] => 33.5
[qty] => 25
[category] => c2
)
[102] => Array
(
[name] => p4
[price] => 10.50
[qty] => 8
[category] => c2
)
)

hope this helps
<?php
$arr1 = [
51 => [
'name' => 'p1',
'price' => '20',
'qty' => '10',
'category' => 'c1'
],
3 => [
'name' => 'p2',
'price' => '10.50',
'qty' => '3',
'category' => 'c2'
]
];
$arr2 = [
3 => [
'name' => 'p3',
'price' => '23',
'qty' => '22',
'category' => 'c1'
],
102 => [
'name' => 'p4',
'price' => '10.50',
'qty' => '8',
'category' => 'c2'
]
];
$result = [];
foreach([$arr1, $arr2] as $arr) {
$keysFromCurrentArray = array_keys($arr);
foreach ($keysFromCurrentArray as $key) {
if(array_key_exists($key, $result)) {
$result[$key] = [
$result[$key]['name'] = $arr[$key]['name'],
$result[$key]['price'] += $arr[$key]['price'],
$result[$key]['qty'] += $arr[$key]['qty'],
$result[$key]['category'] = $arr[$key]['category'],
];
} else {
$result[$key] = $arr[$key];
}
}
}
var_export($result);
output :
array (
51 =>
array (
'name' => 'p1',
'price' => '20',
'qty' => '10',
'category' => 'c1',
),
3 =>
array (
0 => 'p3',
1 => 33.5,
2 => 25,
3 => 'c1',
),
102 =>
array (
'name' => 'p4',
'price' => '10.50',
'qty' => '8',
'category' => 'c2',
),
)

Using array merge in loop is NOT optimal
You can put arrays in one like this:
$arrays = [ [1, 2], [2, 3], [5,8] ];
And then:
$merged = array_merge([], ...$arrays);

Related

PHP - (Almost) Flatten multidimensional array recursively

I am trying to change the following array to an almost flat array. So id 4 would be in the first level of the array, as would id 6 and 5, but still have their own index so I can tell which page is which. But with the same order as they have now. I presume that the solution would be some sort of recursive PHP function but I haven't a clue how to do this.
Array
(
[0] => Array
(
[id] => 2
[identifier] => External URL
[parent] => 0
[sortOrder] => 1
[depth] => 0
)
[1] => Array
(
[id] => 3
[identifier] => First Team
[parent] => 0
[sortOrder] => 2
[depth] => 0
[children] => Array
(
[0] => Array
(
[id] => 4
[identifier] => League tables
[parent] => 3
[sortOrder] => 0
[depth] => 1
[children] => Array
(
[0] => Array
(
[id] => 6
[identifier] => British and Irish Cup Tables
[parent] => 4
[sortOrder] => 24
[depth] => 2
)
[1] => Array
(
[id] => 5
[identifier] => Greene King IPA Championship
[parent] => 4
[sortOrder] => 25
[depth] => 2
)
)
)
)
)
[2] => Array
(
[id] => 1
[identifier] => Home
[parent] => 0
[sortOrder] => 25
[depth] => 0
)
)
<?php
$data = [
[
'id' => 1,
'name' => 'one',
'children' =>
[
[
'id' => 2,
'name' => 'two',
'children' =>
[
[
'id' => 4,
'name' => 'four'
]
]
],
[
'id' => 3,
'name' => 'three',
'children' =>
[
[
'id' => 5,
'name' => 'five'
]
]
]
]
],
[
'id' => 6,
'name' => 'six'
]
];
$stanley = [];
$flatten = function(array $data) use (&$flatten, &$stanley) {
foreach($data as $k => $v) {
if(isset($v['children'])) {
$flatten($v['children']);
unset($v['children']);
}
$stanley[] = $v;
}
};
$flatten($data);
var_export($stanley);
Output:
array (
0 =>
array (
'id' => 4,
'name' => 'four',
),
1 =>
array (
'id' => 2,
'name' => 'two',
),
2 =>
array (
'id' => 5,
'name' => 'five',
),
3 =>
array (
'id' => 3,
'name' => 'three',
),
4 =>
array (
'id' => 1,
'name' => 'one',
),
5 =>
array (
'id' => 6,
'name' => 'six',
),
)
I have found the solution! I built a recursive PHP function which utilised the depth index to track which level each of the items are while still keeping the array flat (ish).
function dropdownNavigationTree($array) {
$response = [];
foreach($array as $page) {
if (!is_array($page['children'])) {
$response[$page['id']] = ($page['depth'] > 0 ? str_repeat("-", $page['depth']).' ' : FALSE).$page['identifier'];
} else {
$response[$page['id']] = ($page['depth'] > 0 ? str_repeat("-", $page['depth']).' ' : FALSE).$page['identifier'];
$children = dropdownNavigationTree($page['children']);
$response = $response + $children;
}
}
return $response;
}

merge two arrays by specific fields

I have an array that looks like
$firstArray
[0] => Array(
[ID] => 1
[Fruit] => Apple
[State] => Ohio
)
[1] => Array(
[ID] => 2
[Fruit] => Orange
[State] => Hawaii
)
[2] => Array(
[ID] => 3
[Fruit] => Orange
[State] => Vermont
)
And another array which looks like
$secondArray
[0] => Array(
[ID] => 1
[description] => This is sample description
[Price] => 20
)
[1] => Array(
[ID] => 1
[Fruit] => This is sample description 2
[Price] => 15
)
[2] => Array(
[ID] => 2
[Fruit] => This is the second description
[Price] => 100
)
[3] => Array(
[ID] => 2
[Fruit] => This is the second description 2
[Price] => 50
)
[4] => Array(
[ID] => 3
[Fruit] => This is the third description
[Price] => 99
)
I have used
$newArray = array_merge_recursive($firstArray, $secondArray);
This has only appended entries from the second array to the end of the first array ideally i would want the new array to look like this
[0] => Array(
[ID] => 1
[Fruit] => Apple
[State] => Ohio
[description]
Array(
[0] => This is sample description
[1] => This is sample description 2
)
[price]
Array(
[0] => 20
[1] => 15
)
[1] => Array(
[ID] => 1
[Fruit] => Apple
[State] => Ohio
[description]
Array(
[0] => This is the second description
[1] => This is the second description 2
)
[price]
Array(
[0] => 100
[1] => 50
)
Essentially the new array should be combined on the ID and create nested arrays from the second array.
See if this makes sense. https://iconoun.com/demo/temp_jumpman.php
<?php // demo/temp_jumpman.php
/**
* Dealing with PHP nested arrays
*
* https://stackoverflow.com/questions/45145282/merge-two-arrays-by-specific-fields
*/
error_reporting(E_ALL);
echo '<pre>';
// TEST DATA CREATED FROM THE POST AT STACK - ID, Fruit, State
$first = Array(
'0' => [
'ID' => '1',
'Fruit' => 'Apple',
'State' => 'Ohio',
],
'1' => [
'ID' => '2',
'Fruit' => 'Orange',
'State' => 'Hawaii',
],
'2' => [
'ID' => '3',
'Fruit' => 'Orange',
'State' => 'Vermont',
],
);
// TEST DATA CREATED FROM THE POST AT STACK - ID, description, Price
$second = Array(
'0' => [
'ID' => '1',
'description' => 'This is sample description',
'Price' => '20',
],
'1' => [
'ID' => '1',
'description' => 'This is sample description 2',
'Price' => '15',
],
'2' => [
'ID' => '2',
'description' => 'This is the second description',
'Price' => '100',
],
'3' => [
'ID' => '2',
'description' => 'This is the second description 2',
'Price' => '50',
],
'4' => [
'ID' => '3',
'description' => 'This is the third description',
'Price' => '99',
],
);
$out = [];
foreach ($first as $arr)
{
// PLACEHOLDERS FOR THE FOUND DATA FROM THE SECOND ARRAY
$arr['description'] = [];
$arr['Price'] = [];
$id = $arr['ID']; // THE ID WE WANT IN THE SECOND ARRAY
foreach ($second as $idp)
{
if ($idp['ID'] == $arr['ID'])
{
$arr['description'][] = $idp['description'];
$arr['Price'][] = $idp['Price'];
}
}
$out[] = $arr;
}
print_r($out);

PHP - Merge 2 multidimensional array based on value

Currently, I have 2 multidimensional array and I'm looking to combine them into one giant array where the value's name in array 1 matches the value's name in array 2.
The array's look as followed...
Array1
(
[0] => Array
(
[id] => 1
[name] => test1
[desc] => test_desc
[quantity] => 3
)
[1] => Array
(
[id] => 2
[name] => test2
[desc] => test_desc
[quantity] => 33
)
)
Array2
(
[0] => Array
(
[holder] => 'John'
[name] => test1
[desc] => test_desc
[location] => ATL
)
[1] => Array
(
[holder] => 'Jackie'
[name] => test3
[desc] => test_desc
[location] => SF
)
)
I'm looking to merge the arrays where the 'name' column in array1 matches in array2 and also combine the columns in array's 1 & 2 into the final array. This should look like...
FinalArray
(
[0] => Array
(
[id] => 1
[holder] => 'John'
[name] => test1
[desc] => test_desc
[location] => ATL
[quantity] => 3
)
[1] => Array
(
[holder] => 'Jackie'
[name] => test3
[desc] => test_desc
[location] => SF
)
[2] => Array
(
[id] => 2
[name] => test2
[desc] => test_desc
[quantity] => 33
)
)
Where the "test1" combines the different columns across the 2 arrays into a new array inside the "FinalArray". I've tried researching some ideas with array_merge and array_merge_recursive but I'm not entirely sure if I'm going in the correct direction. Thanks in advance.
Try like this
$array1=[['id' => 1,'name' => 'test1','desc' => 'test_desc','quantity' => 3],
['id' => 2,'name' => 'test2','desc' => 'test_desc','quantity' => 33]];
$array2=[['holder' => 'John','name' => 'test1','desc' => 'test_desc','location' => 'ATL'],
['holder' => 'Jackie','name' => 'test3','desc' => 'test_desc','location' => 'SF']];
$final=[];
foreach ($array1 as $key1=>$data1){
foreach ($array2 as $key2=>$data2){
if($data1['name']==$data2['name']){
$final[]=$data1+$data2;
unset($array1[$key1]);
unset($array2[$key2]);
}
}
}
if(!empty($array1)){
foreach ($array1 as $value){
$final[]=$value;
}
}
if(!empty($array2)){
foreach ($array2 as $value){
$final[]=$value;
}
}
It will give output as
One more solution
function merge_by_name(array $arr1, array $arr2) {
$result = [];
foreach ($arr1 as $value) {
$key = array_search($value['name'], array_column($arr2, 'name'));
if($key !== false) {
$result[] = array_merge($value, $arr2[$key]);
unset($arr2[$key]);
} else {
$result[] = $value;
}
}
$result = array_merge($result, $arr2);
return $result;
}
Test
$arr1 = [
[
'id' => 1,
'name' => 'test1',
'desc' => 'test_desc',
'quantity' => 3
],
[
'id' => 2,
'name' => 'test2',
'desc' => 'test_desc',
'quantity' => 33
],
];
$arr2 = [
[
'holder' => 'John',
'name' => 'test1',
'desc' => 'test_desc',
'location' => 'ATL'
],
[
'holder' => 'Jackie',
'name' => 'test3',
'desc' => 'test_desc',
'location' => 'SF'
],
];
var_export(merge_by_name($arr1, $arr2));
Result
array (
0 =>
array (
'id' => 1,
'name' => 'test1',
'desc' => 'test_desc',
'quantity' => 3,
'holder' => 'John',
'location' => 'ATL',
),
1 =>
array (
'id' => 2,
'name' => 'test2',
'desc' => 'test_desc',
'quantity' => 33,
),
2 =>
array (
'holder' => 'Jackie',
'name' => 'test3',
'desc' => 'test_desc',
'location' => 'SF',
),
)

PHP combine arrays on same level

So, I am sending data from View to Controller and need to save all (multiple) data in DB.
in view I am using category[], status_number[] and name[] to collect data, then I got this:
[
'category' => [
(int) 0 => 'c',
(int) 1 => 'c1',
(int) 2 => 'c2'
],
'status_number' => [
(int) 0 => 'sn',
(int) 1 => 'sn1',
(int) 2 => 'sn2'
],
'name' => [
(int) 0 => 'n',
(int) 1 => 'n1',
(int) 2 => 'n2'
]
]
now I need to transform (combine) this array so that I can store it to DB in this structure
[
'(int) 0' => [
category => 'c',
status_number => 'sn',
name => 'n'
],
'(int) 1' => [
category => 'c1',
status_number => 'sn1',
name => 'n1'
],
'(int) 2' => [
category => 'c2',
status_number => 'sn2',
name => 'n2'
]
]
You can try something like that:
<?php
$array = [
'category' => [
'c',
'c1',
'c2'
],
'status_number' => [
'sn',
'sn1',
'sn2'
],
'name' => [
'n',
'n1',
'n2'
]
];
$result = [];
array_walk($array, function($data, $key) use (&$result){
foreach($data as $numericKey => $value) {
$result[$numericKey][$key] = $value;
}
});
print_r($result);
As the result it gives:
Array
(
[0] => Array
(
[category] => c
[status_number] => sn
[name] => n
)
[1] => Array
(
[category] => c1
[status_number] => sn1
[name] => n1
)
[2] => Array
(
[category] => c2
[status_number] => sn2
[name] => n2
)
)

Have the following array merged

I have the following array:
Array
(
[0] => Array
(
[Vendor_ID] => 1
[Quantity] => 55
)
[1] => Array
(
[Vendor_ID] => 1
[Quantity] => 55
)
[2] => Array
(
[Vendor_ID] => 1
[Quantity] => 55
)
[3] => Array
(
[Vendor_ID] => 3
[Quantity] =>
)
[4] => Array
(
[Vendor_ID] => 3
[Quantity] =>
)
[5] => Array
(
[Vendor_ID] => 3
[Quantity] =>
)
[6] => Array
(
[Vendor_ID] => 4
[Quantity] =>
)
[7] => Array
(
[Vendor_ID] => 4
[Quantity] =>
)
[8] => Array
(
[Vendor_ID] => 4
[Quantity] =>
)
)
Which is being created with the following code:
$Display_Arr = array();
$Tick = 0;
foreach ($_POST['product'] AS $_1){
if (!in_array($_1['vendor_id'], $Display_Arr)){
$Display_Arr[$Tick] = array(
"Vendor_ID" => $_1['vendor_id'],
"Quantity" => ""
);
$Display_Arr[$Tick]["Quantity"] .= $_1['quantity'];
}else{
$Display_Arr[$Tick]["Quantity"] .= $_1['quantity'];
}
++$Tick;
}
echo "<pre>";
print_r($Display_Arr);
echo "</pre>";
But I am not getting my desired output, which is:
Array
(
[0] => Array
(
[Vendor_ID] => 1
[Quantity] => 55,55,55
)
[1] => Array
(
[Vendor_ID] => 3
[Quantity] =>
)
[2] => Array
(
[Vendor_ID] => 4
[Quantity] =>
)
)
Where am I going wrong with this?
#mathielo
The current output is:
Array
(
[1] => Array
(
[Vendor_ID] => 1
[Quantity] => 55
)
[3] => Array
(
[Vendor_ID] => 3
[Quantity] =>
)
[4] => Array
(
[Vendor_ID] => 4
[Quantity] =>
)
)
Whereas, i'm trying to obtain:
[0] => Array
(
[Vendor_ID] => 1
[Quantity] => 55,55,55
)
If I got it right, what you need is this:
EDIT: Just made some tests and got it right this time:
$Display_Arr = array();
foreach ($_POST['product'] AS $_1){
if (!array_key_exists($_1['Vendor_ID'], $Display_Arr)){
$Display_Arr[$_1['Vendor_ID']] = array(
"Vendor_ID" => $_1['Vendor_ID'],
"Quantity" => $_1['Quantity']
);
}else{
if(!empty($_1['Quantity']))
$Display_Arr[$_1['Vendor_ID']]["Quantity"] .= ",{$_1['Quantity']}";
}
}
echo "<pre>";
print_r($Display_Arr);
echo "</pre>";
The main problem was in if (!in_array($_1['vendor_id'], $Display_Arr)). PHP's in_array() checks for given needle in the array values, and we were trying to match to the Vendor_ID value stored in the outer array keys. That was fixed using array_key_exists().
EDIT 2: I used this for test data:
$_POST['product'] = array(
0 => array(
'Vendor_ID' => 1,
'Quantity' => 55
),
1 => array(
'Vendor_ID' => 1,
'Quantity' => 55
),
2 => array(
'Vendor_ID' => 1,
'Quantity' => 55
)
,
3 => array(
'Vendor_ID' => 3,
'Quantity' => ''
),
4 => array(
'Vendor_ID' => 3,
'Quantity' => ''
),
5 => array(
'Vendor_ID' => 3,
'Quantity' => ''
),
6 => array(
'Vendor_ID' => 4,
'Quantity' => ''
),
7 => array(
'Vendor_ID' => 4,
'Quantity' => ''
),
8 => array(
'Vendor_ID' => 4,
'Quantity' => ''
)
);
You won't be needing $Tick anymore, as you could use Vendor_ID as keys for the outer array.
Looks like the easiest way to solve this would be to first aggregate the vendor quantities, and then build the final array with the keys that you are using.
I am assuming the input looks something like this:
$_POST['product'] = [
['vendor_id' => 1, 'quantity' => 55],
['vendor_id' => 1, 'quantity' => 55],
['vendor_id' => 1, 'quantity' => 55],
['vendor_id' => 3, 'quantity' => null],
['vendor_id' => 3, 'quantity' => null],
['vendor_id' => 3, 'quantity' => null],
['vendor_id' => 4, 'quantity' => null],
['vendor_id' => 4, 'quantity' => null],
['vendor_id' => 4, 'quantity' => null],
];
Aggregating the quantities:
$aggregates = [];
foreach ($_POST['product'] as $product) {
$id = $product['vendor_id'];
if ( ! isset($aggregates[$id])) {
$aggregates[$id] = [];
}
if ($product['quantity'] > 0) {
$aggregates[$id][] = $product['quantity'];
}
}
The aggregates array should now look like this:
$aggregates = [
1 => [
0 => 55,
1 => 55,
2 => 55,
],
3 => [], // Empty
4 => [], // Empty
];
As you can see the data is now neatly organized and ready to be put into any format you want. Using the keys that you use in your question it is as simple as:
$output = [];
foreach ($aggregates as $vid => $qty) {
$quantity = implode(',', $qty);
$output[] = ['Vendor_ID' => $vid, 'Quantity' => $quantity];
}
The output should now look like this:
$output = [
['Vendor_ID' => 1, 'Quantity' => '55,55,55'],
['Vendor_ID' => 3, 'Quantity' => ''],
['Vendor_ID' => 4, 'Quantity' => ''],
];
This will output exactly what you are looking for although the output of the last answer (Sverri M. Olsen) is more useful. Here you get the quantities as a string while with Sverri's method you get an array in first place.
$Display_Arr = array();
$vendors=array();
foreach ($_POST['product'] AS $_1){
if (!in_array($_1['vendor_id'],$vendors)){
$vendors[]=$_1['vendor_id'];
$Display_Arr[sizeof($vendors)-1] = array(
"Vendor_ID" => $_1['vendor_id'],
"Quantity" => $_1['quantity']
);
}
else{
$vendorKey=array_search($_1['vendor_id'],$vendors);
$Display_Arr[$vendorKey]["Quantity"] .=(!empty($Display_Arr[$vendorKey]["Quantity"])?',':null).$_1['quantity'];
}
}

Categories