Sum array values by attribute name - php

I want to sum count values with same code.
This is my array:
$data = array(
array(
'code' => 02,
'count' => 8
),
array(
'code' => 03,
'count' => 1
),
array(
'code' => 03,
'count' => 1
),
array(
'code' => 03,
'count' => 7
),
array(
'code' => 11,
'count' => 1
),
array(
'code' => 11,
'count' => 5
),
array(
'code' => 17,
'count' => 4
),
array(
'code' => 17,
'count' => 2
),
array(
'code' => 17,
'count' => 8
)
);
Now I tried to group the array to sum the count with same code, but I think I'm wrong:
$new_data = [];
foreach($data as $k => $v){
$total = 0;
$new_data[$v['code']] = array(
'ttl' => $v['count'] + $total,
);
}
echo '<pre>';
print_r($new_data);
echo '</pre>';
What is the correct code for this? Thanks.

using isset will avoid undefined offset error:
$new_data = [];
foreach($data as $k => $v){
if (!isset($new_data[$v['code']]['ttl'])){
$new_data[$v['code']]['ttl'] = 0;
}
$new_data[$v['code']]['ttl'] += $v['count'];
}
print_r($new_data);

Assuming you want the keys in $new_data to to be the unique codes, and the values to be an an array with a key of ttl whose value is the sum of the counts for that particular code:
$new_data = [];
foreach($data as $v){
if (!array_key_exists($v['code'], $new_data)) {
$new_data[$v['code']]['ttl'] = $v['count'];
} else {
$new_data[$v['code']]['ttl'] += $v['count'];
}
}

I think this is what you want as output:
Array
(
[2] => Array
(
[ttl] => 8
)
[3] => Array
(
[ttl] => 9
)
[11] => Array
(
[ttl] => 6
)
[17] => Array
(
[ttl] => 14
)
)
If so, you can do minor modifications to your code such as this:
$new_data = [];
foreach ($data as $d) {
if (isset($new_data[$d['code']]['ttl'])) {
$new_data[$d['code']]['ttl'] += $d['count'];
} else {
$new_data[$d['code']]['ttl'] = $d['count'];
}
}

Related

How to combine the same values in an array in foreach loop in php

i want to combine the values of array having same index name in foreach loop..
i tried array_combine but it returns the single array.
$data = $_POST['variable']; //it contain the values in an array
$result=array();
foreach ($data as $mycat){
$result = array_merge($result, $mycat);
}
echo "<pre>";print_r($result);echo "</pre>";
it returns only data in single array
Array
(
[vendor] => 1-Open Market
[priority] => 2
[demand_for_id] => 9
[ims_allocation_details_id] => 148
[temp_demand_id] => 1
)
as shown in attached picture item names are same, so when item names are same i want to combine the total values in foreach and insert only one record into database instead to two
enter image description here
the contents of $_POST['variable']; are
Array
(
[2] => Array
(
[vendor] => 1-Open Market
[temp_demand_id] => 6
[priority] => 1
[item_name] => BAJRA MOTI
[amount] => 1000
[demand_for_id] => 9
[ims_allocation_details_id] => 153
)
[1] => Array
(
[vendor] => 1-Open Market
[temp_demand_id] => 1
[priority] => 2
[item_name] => BAJRA MOTI
[amount] => 2500
[demand_for_id] => 9
[ims_allocation_details_id] => 148
)
)
You should replace
$result = array_merge($result, $mycat);
with
$result[] = array_merge($result, $mycat);
and it will not be single
UPDATE
$result = array();
foreach ($data as $mycat) {
if(!isset($result[$mycat['item_name']])) {
$result[$mycat['item_name']] = $mycat;
} else {
//do if needed
}
}
echo "<pre>";print_r($result);echo "</pre>";
You can create a custom function to solve your problem.
Example:
<?php
$array = [
[
'vendor' => '1-Open Market',
'temp_demand_id' => 6,
'priority' => 1,
'item_name' => 'BAJRA MOTI',
'amount' => 1000,
'demand_for_id' => 9,
'ims_allocation_details_id' => 153,
],
[
'vendor' => '1-Open Market',
'temp_demand_id' => 1,
'priority' => 2,
'item_name' => 'BAJRA MOTI',
'amount' => 2500,
'demand_for_id' => 9,
'ims_allocation_details_id' => 148,
],
[
'vendor' => '1-Open Market',
'temp_demand_id' => 5,
'priority' => 3,
'item_name' => 'BAJRA MOTI',
'amount' => 1000,
'demand_for_id' => 11,
'ims_allocation_details_id' => 200,
],
];
function array_merge_recursive_custom($array) {
$processed = null;
foreach ($array as &$subArray) {
if (empty($processed)) {
$processed = $subArray;
continue;
}
foreach ($subArray as $key => $value) {
if (is_numeric($value)) {
$subArray[$key] += $processed[$key];
}
}
$processed = $subArray;
}
return end($array);
}
var_dump(array_merge_recursive_custom($array));

PHP custom array merge on bases of same value and sum of value

I have array like as follow,
Array(
[0] => Array(
[account] => 251234567890,
[price] => 83
) [1] => Array(
[account] => 251234567890,
[price] => 27
) [2] => Array(
[account] => 251234564526,
[price] => 180
) [3] => Array(
[account] => 251234567890,
[price] => 40
)
)
now with i want to merge array with same account and sum of it's particular price.
I want output array like this,
Array(
[251234567890] => Array(
[account] => 251234567890,
[price] => 150
) [251234564526] => Array(
[account] => 251234564526,
[price] => 180
)
)
I have tried like this,
$res = array();
$k = 0;
foreach ($to_account as $vals) {
if (array_key_exists($vals['account'], $res)) {
$res[$k]['price'] += $vals['price'];
$res[$k]['account'] = $vals['account'];
$k++;
} else {
$res[$k] = $vals;
$k++;
}
}
As here in input array only two unique account is present so output array should be of that two account with sum of it's price
I have seen something like this in python from here but it want be helpful as it is in python i want it in php i hope someone can help me in this
Thank you
I would do this in two steps, first key by the account and then convert to the output format that you want:
$data = [
[
'account' => 251234567890,
'price' => 83
],
[
'account' => 251234567890,
'price' => 27
],
[
'account' => 251234564526,
'price' => 180
],
[
'account' => 251234567890,
'price' => 40
],
];
$keyed = [];
foreach ($data as $item) {
if (!isset($keyed[$item['account']])) {
$keyed[$item['account']] = 0;
}
$keyed[$item['account']] += $item['price'];
}
$merged = [];
foreach ($keyed as $account => $price) {
$merged[] = compact('account', 'price');
}
print_r($merged);
Or, a more functional solution (which I like, but is somewhat harder to understand):
$keyed = array_reduce($data, function ($carry, $item) {
if (!isset($carry[$item['account']])) {
$carry[$item['account']] = 0;
}
$carry[$item['account']] += $item['price'];
return $carry;
}, []);
$merged = array_map(function ($account, $price) {
return compact('account', 'price');
}, array_keys($keyed), $keyed);
what about if you try to do something like:
$arr = array(
0 => array(
'account' => 251234567890,
'price' => 83
), 1 => array(
'account' => 251234567890,
'price' => 27
), 2 =>array(
'account' => 251234564526,
'price' => 180
), 3 => array(
'account' => 251234567890,
'price' => 40
)
);
foreach($arr as $key => $value) {
$newArr[$value['account']][] = $value['price'];
}
foreach($newArr as $key => $value) {
$finalArr[] = array('account'=>$key,'price'=>array_sum($value));
}
$finalArr:
Array ( [0] => Array (
[account] => 251234567890
[price] => 150 )
[1] => Array (
[account] => 251234564526
[price] => 180 ) )
By assigning temporary keys, you can determine whether you are dealing with the first occurrence or not and then use the appropriate technique to either store the whole subarray or merely add value to the price element of the subarray.
Code: (Demo)
$to_account = [
[ 'account' => 251234567890, 'price' => 83 ],
[ 'account' => 251234567890, 'price' => 27 ],
[ 'account' => 251234564526, 'price' => 180 ],
[ 'account' => 251234567890, 'price' => 40 ]
];
foreach ($to_account as $row) {
if (!isset($result[$row['account']])) {
$result[$row['account']] = $row;
} else {
$result[$row['account']]['price'] += $row['price'];
// imitate the above line if there was another column to sum
}
}
var_export($result);
Output:
array (
251234567890 =>
array (
'account' => 251234567890,
'price' => 150,
),
251234564526 =>
array (
'account' => 251234564526,
'price' => 180,
),
)
This method does not bother to overwrite redundant account element values. To reindex the output array, merely call array_values() on it.
#Jeroen Noten your answer is useful for me but i have solved it my own like this,
$final_payment_array = array();
foreach ($to_account as $vals) {
if (array_key_exists($vals['account'], $final_payment_array)) {
$final_payment_array[$vals['account']]['price'] += $vals['price'];
$final_payment_array[$vals['account']]['account'] = $vals['account'];
} else {
$final_payment_array[$vals['account']] = $vals;
}
}
I think this one is the best solution in performance wise
Thank you
Here is my solution. You can try this
$myArray = array(
0 => array(
account => 251234567890,
price => 83,
),
1 => array(
account => 251234567890,
price => 27,
),
2 => array(
account => 251234564526,
price => 180,
),
3 => array(
account => 251234567890,
price => 40,
),
);
$keyed = [];
foreach ($myArray as $item) {
if (!isset($keyed[$item['account']])) {
$keyed[$item['account']] = 0;
}
$keyed[$item['account']] += $item['price'];
}
$merged = [];
foreach ($keyed as $account => $price) {
$merged[] = compact('account', 'price');
}
print_r($merged);
https://eval.in/506410

remove duplicate values from multidimensional array by single value

Ok the thing is, Ive read and tried a lot of solutions found here based on complete duplicateness, BUT I need something a little bit different and cant figure it out...
Because I only want to get and remove the duplicate value if only 1 of the array values is duplicate.
And also later combine the two but that's not that difficult.
$a = array(
array(
'id' => 1,
'qty' => 1
),
array(
'id' => 0,
'qty' => 1
),
array(
'id' => 1,
'qty' => 2
)
);
What I want the outcome to be:
$b = array(
array(
'id' => 1,
'qty' => 3
),
array(
'id' => 0,
'qty' => 1
)
);
You can do something like the following:
<?php
$a = array(
array(
'id' => 1,
'qty' => 1
),
array(
'id' => 0,
'qty' => 1
),
array(
'id' => 1,
'qty' => 2
)
);
$idsList = array();
$res = array();
foreach ($a as $arr){
if (!in_array($arr['id'], $idsList)){
$res[$arr['id']] = $arr;
$idsList[] = $arr['id'];
}
else{
$res[$arr['id']]['qty'] += $arr['qty'];
}
}
echo "<pre>";
print_r($res);
To get array like that:
Array
(
[1] => Array
(
[id] => 1
[qty] => 3
)
[0] => Array
(
[id] => 0
[qty] => 1
)
)
Checkout This DEMO: http://codepad.org/UP0G7WnE
$a = array(
array(
'id' => 1,
'qty' => 1
),
array(
'id' => 0,
'qty' => 1
),
array(
'id' => 1,
'qty' => 2
)
);
$b = array();
$ids = array();
for($i = 0; $i < count($a); $i++)
{
if(in_array($a[$i]['id'], $ids))
{
$j = array_search($a[$i]['id'], array_values($ids));
$b[$j]['qty'] += $a[$i]['qty'];
}
else
{
$b[$i]['id'] = $a[$i]['id'];
$b[$i]['qty'] = $a[$i]['qty'];
$ids[] = $a[$i]['id'];
}
}
echo "<pre>";
print_r($b);
This could be a solution:
$temp = array();
foreach ($a as $data){
if (isset($temp[$data['id']])){
$temp[$data['id']] += $data['qty'];
} else {
$temp[$data['id']] = $data['qty'];
}
}
// Format array
$b = array();
foreach ($temp as $id => $qty){
$b[] = array(
'id' => $id,
'qty' => $qty
);
}
Output will be:
Array
(
[0] => Array
(
[id] => 1
[qty] => 3
)
[1] => Array
(
[id] => 0
[qty] => 1
)
)

Find similar subarrays in some arrays

Have some arrays:
$a = array(
0 => array('value' => 1000, 'name' => 'AA1'),
1 => array('value' => 2000, 'name' => 'AA2'),
2 => array('value' => 3000, 'name' => 'AA3'),
3 => array('value' => 4000, 'name' => 'AA4'),
);
$b = array(
0 => array('value' => 1000, 'name' => 'BB1'),
1 => array('value' => 3000, 'name' => 'BB2'),
2 => array('value' => 1700, 'name' => 'BB3'),
3 => array('value' => 1200, 'name' => 'BB4'),
);
$c = array(
0 => array('value' => 3000, 'name' => 'CC1'),
1 => array('value' => 4000, 'name' => 'CC2'),
2 => array('value' => 4300, 'name' => 'CC3'),
3 => array('value' => 5000, 'name' => 'CC4'),
);
How can create a new array with the same variants from arrays $a, $b and $c? And order it by 'value' field..
$d = array(
0 => array('value' => 3000, 'name' => 'AA3');
);
Real example: http://3v4l.org/MAWjd
// Test Data
$timeVariantSerialized = 'a:3:{s:7:"group_a";a:3:{i:0;a:3:{s:10:"id_variant";i:122;s:4:"name";s:13:"3 hour 30 min";s:4:"time";i:12600;}i:1;a:3:{s:10:"id_variant";i:173;s:4:"name";s:6:"3 hour";s:4:"time";i:10800;}i:2;a:3:{s:10:"id_variant";i:271;s:4:"name";s:6:"1 hour";s:4:"time";i:3600;}}s:7:"group_b";a:2:{i:0;a:3:{s:10:"id_variant";i:107;s:4:"name";s:13:"1 hour 30 min";s:4:"time";i:5400;}i:1;a:3:{s:10:"id_variant";i:321;s:4:"name";s:6:"3 hour";s:4:"time";i:10800;}}s:7:"group_c";a:4:{i:0;a:3:{s:10:"id_variant";i:28;s:4:"name";s:6:"1 hour";s:4:"time";i:3600;}i:1;a:3:{s:10:"id_variant";i:98;s:4:"name";s:6:"3 hour";s:4:"time";i:10800;}i:2;a:3:{s:10:"id_variant";i:157;s:4:"name";s:6:"2 hour";s:4:"time";i:7200;}i:3;a:3:{s:10:"id_variant";i:158;s:4:"name";s:13:"1 hour 30 min";s:4:"time";i:5400;}}}';
// Test Data Array
$time_variant = unserialize( $timeVariantSerialized );
$groupsCount = count( $time_variant );
foreach( $time_variant as $groupId => $groupArray )
{
foreach( $groupArray as $groupChildId => $groupChildArray )
{
$timeCountsArray[$groupChildArray['time']][$groupId] = $groupChildId;
}
}
$result = array();
foreach( $timeCountsArray as $time => $groupIdsArray )
{
if( $groupsCount > count( $groupIdsArray ) ) continue;
foreach( $groupIdsArray as $groupId => $groupChildId )
{
$result[$time_variant[$groupId][$groupChildId]['id_variant']]
= $time_variant[$groupId][$groupChildId];
// If you need only one result , uncomment the below break
// break;
}
// If more than 1 time could have variants , comment out below break to get them all
break;
}
ksort( $result );
print_r( $result );
Result Array :
array
(
'98' => array
(
'id_variant' => 98
'name' => 3 hour
'time' => 10800
)
'173' => array
(
'id_variant' => 173
'name' => 3 hour
'time' => 10800
)
'321' => array
(
'id_variant' => 321
'name' => 3 hour
'time' => 10800
)
)
I'm not sure if this is what you want.
The result is a single array with all the repeated values in the given arrays:
//Lets merge them into a big array to work in a easier way;
//It will be a single level array as follow: [a0] => 1000, [a1] => 2000 etc.
$array = array('a' => $a, 'b' => $b, 'c' =>$c);
foreach($array as $letter => $subArray){
foreach($subArray as $key => $values){
$newArray[$letter.$key] = $values['value'];
}
}
$uniques = array_unique($newArray); //getting the non-repeated values
$repeated = array_diff_assoc($newArray, $uniques); // stripping them out
$final = array_unique($repeated); //cleaning the repeated values to just 1 of each
print_r($final);
Result
Array
(
[b0] => 1000
[b1] => 3000
[c1] => 4000
)

Group array rows by one column and only create a subarray from another column if more than one value

How can I group row data from a two-dimensional array and only create a subarray of another column if the respective group contains more than one value?
In other words, I need to group rows by id and conditionally restructure an array of arrays to have a variable depth of either 2 or 3 levels.
Input:
[
['id' => 567, 'value' => 780],
['id' => 676, 'value' => 743],
['id' => 676, 'value' => 721],
['id' => 234, 'value' => 766],
['id' => 234, 'value' => 680]
]
Desired output:
[
['id' => 567, 'value' => 780],
['id' => 676, 'value' => [743, 721]],
['id' => 234, 'value' => [766, 680]]
]
Are you sure you want to have the value as an integer when there is one value and an array when there are more?
<?php
$array = array(
array('id' => 567, 'value' => 780),
array('id' => 676, 'value' => 743),
array('id' => 676, 'value' => 721),
array('id' => 234, 'value' => 766),
array('id' => 234, 'value' => 680)
);
foreach ($array as $item) {
$result[$item['id']][] = $item['value'];
}
foreach ($result as $id => $value) {
if (count($value) > 1) {
$output[] = array(
'id' => $id,
'value' => $value
);
} else {
$output[] = array(
'id' => $id,
'value' => $value[0]
);
}
}
echo '<pre>';
print_r($output);
echo '</pre>';
?>
If not
<?php
$array = array(
array('id' => 567, 'value' => 780),
array('id' => 676, 'value' => 743),
array('id' => 676, 'value' => 721),
array('id' => 234, 'value' => 766),
array('id' => 234, 'value' => 680)
);
foreach ($array as $item) {
$result[$item['id']][] = $item['value'];
}
foreach ($result as $id => $value) {
$output[] = array(
'id' => $id,
'value' => $value
);
}
echo '<pre>';
print_r($output);
echo '</pre>';
?>
try this one
$array['key1'] = array(
0=>array('id'=>567, 'value'=>780),
1=>array('id'=>676, 'value'=>743),
2=>array('id'=>676, 'value'=>721),
3=>array('id'=>234, 'value'=>766),
4=>array('id'=>234, 'value'=>780)
);
foreach($array['key1'] as $subarray){
$group_id = $subarray['id'];
if(!isset($return[$group_id]))
$return[$group_id] = $subarray;
else{
if(is_array($return[$group_id]['value']))
array_push($return[$group_id]['value'], $subarray['value']);
else
$return[$group_id]['value'] = array($subarray['value'], $return[$group_id]['value']);
}
}
// reset grouping keys into 0,1...
$return = array_values($return);
print_r($return);
There, all the work done for you. How easy is that!
//create the array as you have now
$array[0] = ['id'=>567, 'value'=>780];
$array[1] = ['id'=>676, 'value'=>743];
$array[2] = ['id'=>676, 'value'=>721];
$array[3] = ['id'=>234, 'value'=>766];
$array[4] = ['id'=>234, 'value'=>780];
print_r($array);
print chr(10).chr(10);
//create a new array with the values combined on key
$concat = array();
foreach($array as $val) {
$i = $val['id'];
$v = $val['value'];
if (!is_array($concat[$i]))
$concat[$i] = array();
$concat[$i][] = $v;
}
print_r($concat);
print chr(10).chr(10);
//create a new array to show the data as you want.
$newarray = array();
foreach($concat as $key=>$val) {
$t = array();
$t['id'] = $key;
if (count($val)==1)
$t['value'] = $val[0];
else {
$t['value'] = array();
foreach($val as $v)
$t['value'][] = $v;
}
$newarray[] = $t;
}
print_r($newarray);
print chr(10).chr(10);
Result:
Array
(
[0] => Array
(
[id] => 567
[value] => 780
)
[1] => Array
(
[id] => 676
[value] => 743
)
[2] => Array
(
[id] => 676
[value] => 721
)
[3] => Array
(
[id] => 234
[value] => 766
)
[4] => Array
(
[id] => 234
[value] => 780
)
)
Array
(
[567] => Array
(
[0] => 780
)
[676] => Array
(
[0] => 743
[1] => 721
)
[234] => Array
(
[0] => 766
[1] => 780
)
)
Array
(
[0] => Array
(
[id] => 567
[value] => 780
)
[1] => Array
(
[id] => 676
[value] => Array
(
[0] => 743
[1] => 721
)
)
[2] => Array
(
[id] => 234
[value] => Array
(
[0] => 766
[1] => 780
)
)
)
<?php
$arr['key1'] = array(
array(
'id' => 567,
'value' => 780,
),
array(
'id' => 676,
'value' => 743,
),
array(
'id' => 676,
'value' => 721,
),
array(
'id' => 234,
'value' => 766,
),
array(
'id' => 234,
'value' => 780,
),
);
/* handle element merge */
function array_internal_merge_func($a, $b) {
if ( is_array($a['value']) )
$a['value'][] = $b['value'];
else
$a['value'] = array($a['value'], $b['value']);
return $a;
}
/* handle array merge */
function array_internal_merge($array, $key, $merge_func) {
$hashed = array();
$result = array();
foreach ( $array as $idx => $ele )
$hashed[$ele[$key]][] = $idx;
foreach ( $hashed as $key => $idxies ) {
reset($idxies);
$idx0 = current($idxies);
$result[$idx0] = $array[$idx0];
while ( $idx = next($idxies) )
$result[$idx0] = $merge_func($result[$idx0], $array[$idx]);
}
return $result;
}
print_r(array_internal_merge($arr['key1'], 'id', 'array_internal_merge_func'));
This task can certainly be done concisely with one loop.
Use id column values as temporary first level keys. This makes identifying duplicates most efficient and easy.
While iterating:
if a row's id is new to the result array, then push the whole row (in its original, flat structure) into the result array; or
if a row's id was encountered before, then cast the stored row's value element as an array before pushing the current row's value into that subarray.
If you do not want your result to have id values as the first level keys, then call array_values() to re-index the result.
The special action done implemented below is that when casting a scalar or null data type to an array, the value becomes the lone element of the newly formed array. If an array is explicitly cast as an array, then there is no effect on the data structure at all. This is why (array) can be unconditionally applied in the else branch.
Code: (Demo)
foreach ($array as $row) {
if (!isset($result[$row['id']])) {
$result[$row['id']] = $row;
} else {
$result[$row['id']]['value'] = array_merge(
(array) $result[$row['id']]['value'],
[$row['value']]
);
}
}
var_export(array_values($result));
An alternative without array_merge(): (Demo)
foreach ($array as $row) {
if (!isset($result[$row['id']])) {
$result[$row['id']] = $row;
} else {
$result[$row['id']]['value'] = (array) $result[$row['id']]['value'];
$result[$row['id']]['value'][] = $row['value'];
}
}
var_export(array_values($result));
An alternative with array_reduce(): (Demo)
var_export(
array_values(
array_reduce(
$array,
function($result, $row) {
if (!isset($result[$row['id']])) {
$result[$row['id']] = $row;
} else {
$result[$row['id']]['value'] = (array) $result[$row['id']]['value'];
$result[$row['id']]['value'][] = $row['value'];
}
return $result;
}
)
)
);

Categories