I'm needing a way to merge several arrays ( probably around 8 ) and sum any duplicate keys or sub-keys.
For example:
$arr1 = [
"Friday" => ["Breakfast" => 32, "Lunch" => 45],
"Sunday" => ["Lunch" => 12]
];
$arr2 = [
"Sunday" => ["Breakfast" => 7, "Lunch" => 3],
"Monday" => ["Breakfast" => 12]
];
$arr3 = [
"Monday" => ["Breakfast" => 31]
];
And the output should be something like this:
array (
'Friday' =>
array (
'Breakfast' => 32,
'Lunch' => 45,
),
'Sunday' =>
array (
'Lunch' => 15,
'Breakfast' => 7,
),
'Monday' =>
array (
'Breakfast' => 43,
),
);
How could I combine this? I've tried using array_map().
But that seemed to fail with multidimensional arrays like this. Also tried using foreach(), but that got pretty convoluted.
Here's my attempt:
$total = array_map( function( $arr1, $arr2, $arr3 ){
return( $arr1 + $arr2 + $arr3 );
}, $arr1, $arr2, $arr3 );
Try this solution. You can add any count of arrays. But keep names as $arr1-$maxArraysCount
$arr1 = array(
"Friday" => array(
"Breakfast" => 32,
"Lunch" => 45
),
"Sunday" => array(
"Lunch" => 12
)
);
$arr2 = array(
"Sunday" => array(
"Breakfast" => 7,
"Lunch" => 3
),
"Monday" => array(
"Breakfast" => 12
)
);
$arr3 = array(
"Monday" => array(
"Breakfast" => 31
)
);
$maxArraysCount = 8;
$return = array();
for($i = 1; $i < $maxArraysCount; $i++){
$arr = 'arr' . $i;
if(isset($$arr) && is_array($$arr)){
foreach ($$arr as $day => $value) {
foreach ($value as $eat => $count) {
if(!isset($return[$day][$eat])) $return[$day][$eat] = 0;
$return[$day][$eat] = $count + $return[$day][$eat];
}
}
}
}
echo "<pre>";print_r($return);
Here is output:
Array
(
[Friday] => Array
(
[Breakfast] => 32
[Lunch] => 45
)
[Sunday] => Array
(
[Lunch] => 15
[Breakfast] => 7
)
[Monday] => Array
(
[Breakfast] => 43
)
)
Because your data structure is fully associative, array_merge_recursive() will keep your data integrity intact. Once the arrays are merged, you only need to iterate the days' meals, cast the single values as array type (turning them into single-element arrays if not already arrays), then unconditionally all array_sum().
Code: (Demo)
$arr1 = [
"Friday" => ["Breakfast" => 32, "Lunch" => 45],
"Sunday" => ["Lunch" => 12]
];
$arr2 = [
"Sunday" => ["Breakfast" => 7, "Lunch" => 3],
"Monday" => ["Breakfast" => 12]
];
$arr3 = [
"Monday" => ["Breakfast" => 31]
];
$result = [];
foreach (array_merge_recursive($arr1, $arr2, $arr3) as $day => $meals) {
foreach ($meals as $meal => $counts) {
$result[$day][$meal] = array_sum((array)$counts);
}
}
var_export($result);
Output:
array (
'Friday' =>
array (
'Breakfast' => 32,
'Lunch' => 45,
),
'Sunday' =>
array (
'Lunch' => 15,
'Breakfast' => 7,
),
'Monday' =>
array (
'Breakfast' => 43,
),
)
To avoid variable-variables in Oleg's answer, you can stuff each of your input arrays into an array, then merge them (to preserve the duplicated day names).
Code: (Demo)
$result = [];
foreach (array_merge([$arr1], [$arr2], [$arr3]) as $array) {
foreach ($array as $day => $meals) {
foreach ($meals as $meal => $count) {
$result[$day][$meal] = ($result[$day][$meal] ?? 0) + $count;
}
}
}
or more efficiently, prepopulate the result array with your first array.
$result = $arr1;
foreach (array_merge([$arr2], [$arr3]) as $array) {
foreach ($array as $day => $meals) {
foreach ($meals as $meal => $count) {
$result[$day][$meal] = ($result[$day][$meal] ?? 0) + $count;
}
}
}
Related
I'm having this array:
array(
[1] => Array
(
[1111] => Array
(
[one] => 70
[two] => 7.0
)
)
[2] => Array
(
[1111] => Array
(
[one] => 10
[two] => 2.0
)
)
)
And i want it to sum [one] and [two] of the two different arrays and output an array like this:
Array
(
[1111] => Array (
[one] => 80
[two] => 9.0
)
)
Based on the key "1111"
I have tried with the following
$array = array_values( $array );
$sum_array = [];
foreach ( $array as $k => $sub_array ) {
foreach ( $sub_array as $id => $value ) {
$sum_array[$id] += array_key_exists( $id, $sum_array ) ? $sum_array[$id] += $value : $sum_array[$id] = $value;
$sum_array[$id]['two'] += array_sum( $sum_array[$id]['two'] ) / ( 100 * count( $sum_array[$id]['count'] ) );
}
}
But that gives me only the first value like this:
Array
(
[1111] => Array (
[one] => 70
[two] => 7.0
)
)
Can someone please tell me what i'm doing wrong?
You could use the array_reduce to reduce your array to only one element.
The array_reduce function takes two ( sometime three ) parameters. The first one is the array, the second one is a callback with two parameters , the collector, and the current item. If there is a third parameters to the array_reduce function, it will be used to initialize the collector ( like in our case ).
The function will parse each item and do something with it, the collector will be available at each iteration, that's why we use it to keep information of the data, in our case, it's the sum of the values. Once all the item has been iterated over, the function returns the collector.
<?php
$array = [
[
'1111' => [
'one' => 70,
'two' => 7.0
]
],
[
'1111' => [
'one' => 10,
'two' => 2.0
]
]
];
$output = array_reduce($array, function($collector, $item) {
$collector['1111']['one'] += $item['1111']['one'];
$collector['1111']['two'] += $item['1111']['two'];
return $collector;
}, ['1111' => ['one' => 0, 'two' => 0]]);
var_dump($output);
Here is an approach that uses a recursive merge. In the following when merged John's hours become an array. We then need to sum. As James only has one entry his hours do not become an array so we leave them be.
Hopefully the transitional merge output, will give you an idea of the process:
<?php
$items =
[
[
'john' => [
'hours' => 2,
'tips' => 7
]
],
[
'john' => [
'hours' => 3,
'tips' => 10
]
],
[
'james' => [
'hours' => 8,
'tips' => 0
]
]
];
$output = array_merge_recursive(...$items);
var_export($output);
array_walk($output, function(&$v) {
array_walk($v, function(&$v) {
if(is_array($v))
$v = array_sum($v);
});
});
echo "\nResult: \n";
var_export($output);
Output:
array (
'john' =>
array (
'hours' =>
array (
0 => 2,
1 => 3,
),
'tips' =>
array (
0 => 7,
1 => 10,
),
),
'james' =>
array (
'hours' => 8,
'tips' => 0,
),
)
Result:
array (
'john' =>
array (
'hours' => 5,
'tips' => 17,
),
'james' =>
array (
'hours' => 8,
'tips' => 0,
),
)
$total=0;
array_map(function ($item) use ($total)
{
$total += $item['one'] + $item['two'];
}, $array);
echo $total;
Or difference key
$one = array_sum(array_column($array, 'one'));
$two = array_sum(array_column($array, 'two'));
$resultArray = compact('one','two');
```
This is my two multidimensional array and i want get unique value and when same iProduct_id's value is occured then subtraction of fTotal_qty. I need help. Thank you in Advance.
This is Array1
Array(
[0] => Array
(
[iProduct_id] => 1
[fTotal_qty] => 200
)
[1] => Array
(
[iProduct_id] => 4
[fTotal_qty] => 100
)
)
This is Array2
Array
(
[0] => Array
(
[iProduct_id] => 1
[fTotal_qty] => 500
)
[1] => Array
(
[iProduct_id] => 2
[fTotal_qty] => 400
)
[2] => Array
(
[iProduct_id] => 6
[fTotal_qty] => 700
)
[3] => Array
(
[iProduct_id] => 4
[fTotal_qty] => 300
)
[4] => Array
(
[iProduct_id] => 5
[fTotal_qty] => 200
)
)
And i want like this output
iProduct_id = 1, fTotal_qty = 300
iProduct_id = 2, fTotal_qty = 400
iProduct_id = 6, fTotal_qty = 700
iProduct_id = 4, fTotal_qty = 200
You need to use array_map() function in php
array_map(myfunction,array1,array2,array3...)
Here myfunction is the way which will contain logic to do substraction and merging of your items.
array1 , array2 ,array3 are the number of array which may contain your data.
You can do the following:
foreach($array1 as $index => $value) {
$key = array_search($value['iProduct_id'], $array2);
if($key) {
$newArray[$index]['iProduct_id'] = $value['iProduct_id'];
$newArray[$index]['fTotal_qty'] = $array2[$key]['fTotal_qty'] - $value['fTotal_qty'];
}
}
$finalArray = array_diff($array2,$newArray);
var_dump(array_merge($finalArray,$newArray));
I hope it would be helpful.
<?php
$one =
[
[
'id'=>1,
'amount' => 100
],
[
'id'=>2,
'amount' => 200
],
];
$two =
[
[
'id'=>1,
'amount' => 700
],
[
'id'=>2,
'amount' => 800
],
[
'id'=>3,
'amount' => 900
],
];
$one_id_amount = array_column($one, 'amount', 'id');
foreach($result = $two as $k => $v)
$result[$k]['amount'] -= $one_id_amount[$v['id']] ?? 0;
var_export($result);
Output:
array (
0 =>
array (
'id' => 1,
'amount' => 600,
),
1 =>
array (
'id' => 2,
'amount' => 600,
),
2 =>
array (
'id' => 3,
'amount' => 900,
),
)
<?php
$arr1 = array(
array('iProduct_id' => 4,'fTotal_qty' => 100),
array('iProduct_id' => 2,'fTotal_qty' => 100)
);
$arr2 = array(
array('iProduct_id' => 1,'fTotal_qty' => 500),
array('iProduct_id' => 2,'fTotal_qty' => 450),
array('iProduct_id' => 6,'fTotal_qty' => 700),
array('iProduct_id' => 4,'fTotal_qty' => 300),
array('iProduct_id' => 5,'fTotal_qty' => 200)
);
echo "<pre>";
echo "array1 = "; print_r($arr1);
echo "array2 = "; print_r($arr2);
$key = array_column($arr1, 'iProduct_id');
$arraySub = array();
$sub = array();
for ($i=0; $i < count($arr2); $i++) {
if (array_search($arr2[$i]['iProduct_id'],$key) != '' || array_search($arr2[$i]['iProduct_id'],$key) == 0)
{
$arraySub['val1'] = array_search($arr2[$i]['iProduct_id'],$key);
$arraySub['val2'] = $i;
}
$sub[] = $arraySub;
}
foreach ($sub as $value) {
if ($arr1[$value['val1']]['iProduct_id'] != '' && $arr2[$value['val2']]['iProduct_id'] != '') {
if ($arr1[$value['val1']]['iProduct_id'] == $arr2[$value['val2']]['iProduct_id'] ) {
$arr2[$value['val2']]['fTotal_qty'] = abs($arr2[$value['val2']]['fTotal_qty']) - abs($arr1[$value['val1']]['fTotal_qty']);
}
}
}
echo "(array1 - array2) = "; print_r($arr2); // your subtrected value has been stored in arr2
?>
Tested answer:
<?php
$Array1 =
[
[
'iProduct_id'=>1,
'fTotal_qty' => 200
],
[
'iProduct_id'=>4,
'fTotal_qty' => 100
],
];
$Array2 =
[
[
'iProduct_id'=>1,
'fTotal_qty' => 500
],
[
'iProduct_id'=>2,
'fTotal_qty' => 400
],
[
'iProduct_id'=>6,
'fTotal_qty' => 700
],
[
'iProduct_id'=>4,
'fTotal_qty' => 300
],
[
'iProduct_id'=>5,
'fTotal_qty' => 200
],
];
$one_id_amount = array_column($Array1, 'fTotal_qty', 'iProduct_id');
foreach($result = $Array2 as $k => $v)
$result[$k]['fTotal_qty'] -= $one_id_amount[$v['iProduct_id']] ?? 0;
foreach ($result as $line) {
echo "iProduct_id =" . $line['iProduct_id'] . ", fTotal_qty = " . $line['fTotal_qty'] . "<br>";
}
I hope it would be helpful.
I have 2 arrays of arrays which I want to merge by keys for the first step and them sum on the second step - example:
Array
(
[2017-03-01] => Array
(
[apples] => 2
[bananas] => 1
)
[2017-03-02] => Array
(
[apples] => 3
[bananas] => 6
)
[2017-03-03] => Array
(
[apples] => 0
[bananas] => 4
)
}
Array
(
[2017-03-01] => Array
(
[apples] => 3
[bananas] => 2
)
[2017-03-02] => Array
(
[apples] => 4
[bananas] => 7
)
[2017-03-03] => Array
(
[apples] => 1
[bananas] => 5
)
}
Wanted result:
Array
(
[2017-03-01] => Array
(
[apples] => 5
[bananas] => 3
)
[2017-03-02] => Array
(
[apples] => 7
[bananas] => 13
)
[2017-03-03] => Array
(
[apples] => 1
[bananas] => 9
)
}
Is there a command that does that (as a 1 single command) that will avoid looping through the arrays?
No. (obligatory additional characters)
Here's an insanely inefficient way of doing but without using any sort of for foreach or while
$result = array_map(function ($aentry, $key) use ($b) {
$bentry = $b[$key] ?? [];
$result = array_map(function ($value, $key) use ($bentry) {
return [$key, $value + ($bentry[$key] ?? 0) ];
},$aentry, array_keys($aentry));
return [ $key, array_combine(array_column($result, 0), array_column($result, 1)) ];
}, $a,array_keys($a));
$result = array_combine(array_column($result, 0), array_column($result, 1));
Example: http://sandbox.onlinephpfunctions.com/code/4c1dca3057c33dd17d0106666a497c7b08e57038
Solution without for/foreach/... , assuming that all keys are the same, you can do:
$array1 = [
'2017-03-01' => [
'apples' => 2,
'bananas' => 1,
],
'2017-03-02' => [
'apples' => 3,
'bananas' => 6,
],
'2017-03-03' => [
'apples' => 0,
'bananas' => 4,
],
];
$array2 = [
'2017-03-01' => [
'apples' => 3,
'bananas' => 2,
],
'2017-03-02' => [
'apples' => 4,
'bananas' => 7,
],
'2017-03-03' => [
'apples' => 1,
'bananas' => 5,
],
];
array_walk($array1, function(&$subarray1, $key) use($array2) {
array_walk($subarray1, function(&$element, $subkey) use($array2, $key) {
$element += $array2[$key][$subkey];
});
});
Not good performance, just for fun.
Thank you all for your answers, here is my code:
function merge_fruit_data($new_data, $old_data){
// If it's the first time running - return new data as an array
if (empty($old_data)){
return $new_data;
}
else {
foreach ( $new_data as $key => $insert_new_data ) {
if ( !$old_data[$key] ) {
$old_data[$key] = $insert_new_data;
}
else{
$old_data[$key]['apples'] += $insert_new_data['apples'];
$old_data[$key]['bananas'] += $insert_new_data['bananas'];
}
}
}
return $old_data;
}
Efficiency comments are welcome.
This may help you
`$a = array('2017-03-01' => array('apples'=> 2, 'bananas'=>1),
'2017-03-02' => array('apples'=> 3, 'bananas'=>6),
'2017-03-03' => array('apples'=> 0, 'bananas'=>4));
$b=array('2017-03-01' => array('apples'=> 3, 'bananas'=>2),
'2017-03-02' => array('apples'=> 4, 'bananas'=>7),
'2017-03-03' => array('apples'=> 1, 'bananas'=>5));
$sumArray = array();
foreach ($a as $key=>$value) {
$sumArray[$key]['apples']=($a[$key]['apples']+$b[$key]['apples']);
$sumArray[$key]['bananas']=($a[$key]['bananas']+$b[$key]['bananas']);
}
print_r($sumArray);
`
I am a PHP beginner and have the following problem that I completely get stuck. I have an array in this format
Array (
[date] => 0
[author] => 1
[categories] => 1
[tags] => 0
[comments] => 0
[readmore] => 0
)
Now I need to remove all items that are [value] => 0 from that array and get it in this format
Array (
[0] => author
[1] => categories
)
Any input in this is much appreciated.
use array_filter and then array_keys:
$array = array ( 'date' => 0, 'author' => 1, 'categories' => 1, 'tags' => 0, 'comments' => 0, 'readmore' => 0 );
$array = array_filter($array);
print_r(array_keys($array));
output
Array
(
[0] => author
[1] => categories
)
There is a function called array_search() out there. Assuming the only possible values are 0 and 1, you can just serach the whole array for this value:
$array = [
'date' => 0,
'author' => 1,
'categories' => 1,
'tags' => 0,
'comments' => 0,
'readmore' => 0
];
$new_array = array_flip(array_search(1, $array));
So print_r($new_array) will give you your desired result.
You can try something like this:
foreach($array as $item){
if($item == "0"){
unset($item);
}
}
Or some modification with using unset function.
This is also do the job...
$dataSource = array('data' => 0,
'author' => 1,
'categories' => 1,
'tags' => 0,
'comments' => 0,
'readmore' => 0,
);
$updatedDataList = array();
foreach ($dataSource as $key => $value) {
if($value !== 0) {
$updatedDataList[] = $key;
}
}
print_r($updatedDataList);
#savethegold you can save your gold like below :D
<?php
$Array1 = array("date" => 0, "author" => 1, "categories" => 1, "tags" => 0, "comments" => 0, "readmore" => 0 );
foreach ($Array1 as $key => $value) {
if($value == 0){
unset($Array1[$key]);
}
}
$finalArr = array_keys($Array1);
print_r($finalArr);
You can try following code
$yourArray = Array ("date" => 0,"author" => 1, "categories" => 1,"tags" => 0, "comments" => 0,"readmore" => 0 );
$removeZeroFromArray = array(0);
$desiredResult = array_diff($yourArray, $removeZeroFromArray);
echo"<pre>";
print_r(array_keys($desiredResult));
echo"</pre>";
Your output will be like
Array
(
[0] => author
[1] => categories
)
Alternate way should be
$desiredResult = array_filter($yourArray, function($a) { return ($a !== 0); });
Hope it helps!
<?php
$array = array ( 'date' => 0, 'author' => 1, 'categories' => 1, 'tags' => 0, 'comments' => 0, 'readmore' => 0 );
$resutl = [];
foreach($array as $k => $v)
{
if($v != 0)
$result[] = $k;
}
print_r($result);
I have the following multidimensional array:
array(
array(
[id] => 65,
[user_id] => 1,
[total] => 1
),
array(
[id] => 66,
[user_id] => 3,
[total] => 2
),
array(
[id] => 67,
[user_id] => 5,
[total] => 4
),
)
How do I get the array with the highest value for total and I still get the full key Value for the array like this:
array(
[id] => 67,
[user_id] => 5,
[total] => 4
)
Try this:
$total = array();
foreach ($data as $key => $row) {
$total[$key] = $row['total'];
}
// this sorts your $data array by `total` in descending order
// so the max for `total` is the first element
array_multisort($total, SORT_DESC, $data);
And now, use $data[0];
Order the arrays on id using usort():
function cmp($a, $b)
{
return strcmp($b["id"], $a["id"]);
}
usort($arr, 'cmp'); // $arr is your array
Then the first array has your desired values.
See the documentation on usort for more information: http://php.net/manual/en/function.usort.php
$array = [
['id' => 1, 'total' => 1],
['id' => 2, 'total' => 4],
['id' => 3, 'total' => 5],
];
function cmp($a, $b) {
return ($a['total'] < $b['total']) ? 1 : -1;
}
usort($array, 'cmp');
print_r($array[0]); // output ['id' => 3, 'total' => 5]
You can use array_column() with array_search():
$totals = array_column( $array, 'total' );
$result = $array[ array_search( max( $totals ), $totals ) ];
array_column() return an array with 'total' values. Use it to retrieve the key of main array with max total value.
But... what about following array?
$array = array(
array(
'id' => 65,
'user_id' => 1,
'total' => 4
),
array(
'id' => 66,
'user_id' => 3,
'total' => 2
),
array(
'id' => 67,
'user_id' => 5,
'total' => 4
),
array(
'id' => 68,
'user_id' => 6,
'total' => 2
)
);
To filter all max values, you can use this:
$max = max( array_column( $array, 'total' ) );
$result = array_filter
(
$array,
function( $row ) use ( $max )
{
return $row['total'] == $max;
}
);
print_r( $result );
Output:
Array
(
[0] => Array
(
[id] => 65
[user_id] => 1
[total] => 4
)
[2] => Array
(
[id] => 67
[user_id] => 5
[total] => 4
)
)
Put in $max variable max value of 'total' column, then use it to filter original array and retrieve all rows having it as total.
Read more about array_column()
Read more about array_filter()
You can install xdebug for var_dump
and look you array by
var_dump($array);
after you can get needing array by key
$array[3]; //example for question context
or get by foreach for analyses you array
$arrayResult = array();
foreach($array as $_arr) {
if($_arr['user_id'] == 5) {
$arrayResult = $_arr;
}
}
var_dump($arrayResult);
this is example for your question context too