Sum multidimensional associative array values while preserving key names - php

There are many nice Q&A on Stackoverflow on how to take a multidimensional associative array and sum values in it. Unfortunately, I can't find one where the key names aren't lost.
For example:
$arr=array(
array('id'=>'1', 'amount'=>'5'),
array('id'=>'1', 'amount'=>'5'),
array('id'=>'2', 'amount'=>'1'),
array('id'=>'2', 'amount'=>'3')
);
I want the resulting array to look like this:
$result=array(
array('id'=>'1', 'amount'=>'10'),
array('id'=>'2', 'amount'=>'4')
);
Unfortunately the only thing I can figure out how to do is this:
$result = array();
foreach($arr as $amount){
if(!array_key_exists($amount['id'], $arr))
$result[$amount['id']] =0;
$result[$amount['id']] += $amount['amount'];
}
Which when echo'd as follows produces (notice the lack of the keys' words "id" and "amount"):
foreach($result as $id => $amount){
echo $id."==>".$amount."\n";
}
1==>10
2==>4

This is just to show that you already had the data you originally needed, though, the answer you accepted is a better way to deal with it.
You have the following to start with right?
$arr = array(
array('id'=>'1', 'amount'=>'5'),
array('id'=>'1', 'amount'=>'5'),
array('id'=>'2', 'amount'=>'1'),
array('id'=>'2', 'amount'=>'3')
);
Output
Array
(
[0] => Array
(
[id] => 1
[amount] => 5
)
[1] => Array
(
[id] => 1
[amount] => 5
)
[2] => Array
(
[id] => 2
[amount] => 1
)
[3] => Array
(
[id] => 2
[amount] => 3
)
)
Then you run it through the following algorithm:
$summedArr = array();
foreach ($arr as $amount) {
$summedArr['amount'][$amount['id']] += $amount['amount'];
$summedArr['id'][$amount['id']] = $amount['id'];
}
Now, disregarding the Notice warnings that are produced since you are referencing indexes that don't yet exist, this outputs the following:
Output
Array
(
[amount] => Array
(
[1] => 10
[2] => 4
)
[id] => Array
(
[1] => 1
[2] => 2
)
)
Do you see the keys, yet? Because I do.
Now iterate over the array:
foreach ($summedArr as $key => $value) {
echo $k . "==>" . $v . "\n";
}
Output
amount==>Array
id==>Array
That's not what you want, though. You want:
foreach ($summedArr as $key => $arr) {
foreach ($arr as $v) {
echo $key . "==>" . $v;
}
}

Why not use that method, and then reconstruct the array you want at the end?
$results = array();
foreach ($arr as $id=>$amount) {
$results[] = array('id' => $id, 'amount' => $amount);
}
Any other way of doing this would be more computationally expensive.

Related

Replace every string in multidimensional array if conditions matched

Ok so I have an array look like this,
Array
(
[0] => Array
(
[0] => order_date.Year
[1] => =
[2] => 2024
),
[1] => Array
(
[0] => order_date.Quarter
[1] => =
[2] => 1
)
)
What I want to do is, in any element of this multidimensional array I want to replace any string that have a . with removing everything after .
So the new array should look like this,
Array
(
[0] => Array
(
[0] => order_date
[1] => =
[2] => 2024
),
[1] => Array
(
[0] => order_date
[1] => =
[2] => 1
)
)
I have tried doing this,
foreach ($filter as $key => $value) {
if(is_array($value)) {
$variable = substr($value[0], 0, strpos($value[0], "."));
$value[0] = $variable;
}
}
print_r($filter);
I'm getting $value[0] as order_date but can't figure out how to assign it to $filter array without affecting other values in array;
The $value variable is not linked with the original array in the foreach loop.
You can make a reference to the original array by using ampersand "&"
foreach ($filter as $key => &$value) { ... }
Or you can use old school key nesting
$filter[$key][0] = $variable;
Please take a look here https://stackoverflow.com/a/10121508/9429832
this will take off values after . in every element of any multidimensional array.
// $in is the source multidimensional array
array_walk_recursive ($in, function(&$item){
if (!is_array($item)) {
$item = preg_replace("/\..+$/", "", $item);
}
});

Combine values by key in single array

Nothing really does exactly what I want to achieve. I have the following array:
Array(
[0] => Array
(
[chicken] => 7
)
[1] => Array
(
[cheese] => 9
)
[2] => Array
(
[marinade] => 3
)
[3] => Array
(
[cookbook] => 7
)
[4] => Array
(
[chicken] => 11
)
[5] => Array
(
[cheese] => 6
)
[6] => Array
(
[marinade] => 12
)
)
I want to sum all values by their key. If the key is multiple times in the array, like chicken, I want to sum the values.
array
(
[chicken] => 18,
[cheese] => 16
... etc
)
So you'd first need a loop to iterate through the first array to get the second-level arrays. Then you can get the current key and value from each of those arrays, summing the values in a new array associated by the key.
// where the sums will live
$sum = [];
foreach($array as $item) {
$key = key($item);
$value = current($item);
if (!array_key_exists($key, $sum)) {
// define the initial sum of $key as 0
$sum[$key] = 0;
}
// add value to the sum of $key
$sum[$key] += $value;
}
Here simple example i hope it's help you.
$result = array();
foreach($data as $key => $value)
{
$valueKey = key($value);
$result[$valueKey] += $value[$valueKey];
}

Combine two different dimensional arrays PHP

I have two different dimensional arrays.
Array 1:
Array1
(
[0] => Array
(
[id] => 123
[price] => 5
[purchase_time] => 2014/4/10
)
[1] => Array
(
[id] => 123
[price] => 5
[purchase_time] => 2014/5/17
)
)
Array 2:
Array2
(
[0] => 5
[1] => 8
)
I want something like this:
Array
(
[0] => Array
(
[id] => 123
[price] => 5
[purchase_time] => 2014/4/10
[Qty] => 5
)
[1] => Array
(
[id] => 123
[price] => 5
[purchase_time] => 2014/5/17
[Qty] => 8
)
)
Basically the first array is the information I got from a SQL table. The second array contains the quantity for the products sold. I now want to combine these two array together and use the combined array to create a new table. Since these two arrays have different dimensions. I'm not sure how to do it. Here is my try:
$i = 0;
foreach($array1 as $row)
{
$newarray = array_merge($row,$array2[$i]);
$i++;
}
Might be a simpler way, but for fun without foreach:
array_walk($array1, function(&$v, $k, $a){ $v['Qty'] = $a[$k]; }, $array2);
The simplest way is:
$i = 0;
foreach($array1 as &$row) {
$row['Qty'] = $array2[$i++];
}
Or if keys of both arrays are the same (0,1,2...) and array have the same length:
foreach($array1 as $k => &$row) {
$row['Qty'] = $array2[$k];
}
If the $array1 and $array2 are mapped by the same indexes, so they have same length, you can try:
foreach($array2 as $index=>$quantity){
$array1[$index]['Qty'] = $quantity;
}
And it´s done!
If you want to keep the original $array1 untouched, you can make a copy before the foreach.
Create new array and store it there. You can access the value of $array2 because they have the same index of $array1 so you can use the $key of these two arrays.
$array3 = [];
foreach($array1 as $key => $val) {
$array3[] = [
'id' => $val['id'],
'price' => $val['price'],
'purchase_time' => $val['purchase_time'],
'Qty' => $array2[$key]
];
}
print_r($array3);

Merge Array Into Single Outside Loop

I am attempting to do the following. I have the following array "item_code" within an array:
Array
(
[name] => Wes
[email] => no#no.com
[duration] => 2 days
[comment] => stuff
[item_code] => Array
(
[0] => USE4220HP9,USE4220HP8,USE4220HP7,USE4220HP6,USE4220HP5
[1] => USE0463V8E,USE1066KYN,USE0463V7S,USE1066KYS,USE1066KYK
)
)
The item_code array can potentially have multiple keys - more than two. What I want to do is turn the item_code array into a single array where each USExxxxx value is a single key within the array.
I understand how to use something like foreach and turn the example into this:
$serial = $_POST['item_code'];
foreach ($serial as $sn => $id)
{
$finalsn = ($serial[$sn]);
print_r(explode(',', $finalsn));
}
Result
Array
(
[0] => USE4220HP9
[1] => USE4220HP8
[2] => USE4220HP7
[3] => USE4220HP6
[4] => USE4220HP5
)
Array
(
[0] => USE0463V8E
[1] => USE1066KYN
[2] => USE0463V7S
[3] => USE1066KYS
[4] => USE1066KYK
)
But how can I merge these two arrays into one array? I need this to be a single array outside of the loop so that I can pass the values into a single mysql query. I tried with array_merge but having no luck.
You could merge it into a final array using array_merge
$serial = $_POST['item_code'];
$finalArray = Array();
foreach ($serial as $sn => $id)
{
$finalsn = ($serial[$sn]);
print_r(explode(',', $finalsn));
$finalArray = array_merge($finalArray, explode(',', $finalsn));
}
$serial = $_POST['item_code'];
$final_arr=array()
foreach ($serial as $sn => $id)
{
$finalsn = ($serial[$sn]);
$temp_arr=(explode(',', $finalsn));
foreach($temp_arr as $temp){
$final_arr[]=$temp;
}
}
print_r($final_arr;)
Maybe I'm misunderstanding something here, but with this $testArr contains all USE numbers after the iteration.
$serial = $_POST['item_code'];
$finalArr = array();
foreach ($serial as $sn => $id)
{
$tmpStr = ($serial[$sn]);
$tmpArr= explode(',', $tmpStr);
array_push($finalArr,$tmpArr);
}

php - recreate array?

I've "inherited" some data, which I'm trying to clean up. The array is from a database which, apparently, had no keys.
The array itself, is pretty long, so I'm simplifying things for this post...
[0] => Array
(
[id] => 2
[uid] => 130
[eid] => 8
[ename] => Standard
[eaction] => Check
)
[1] => Array
(
[id] => 2
[uid] => 110
[eid] => 8
[ename] => Standard
[eaction] => Check
)
[2] => Array
(
[id] => 2
[uid] => 200
[eid] => 8
[ename] => Standard
[eaction] => Check
)
I'm trying to shift things around so the array is multidimensional and is grouped by ename:
[0] => Array
(
[Standard] => Array
(
[id] => 2
[uid] => 130
[eid] => 8
[eaction] => Check
)
)
[0] => Array
(
[Standard] => Array
(
[id] => 2
[uid] => 130
[eid] => 8
[eaction] => Check
)
)
[0] => Array
(
[Standard] => Array
(
[id] => 2
[uid] => 130
[eid] => 8
[eaction] => Check
)
)
Anyone know how to do something like this?
You can use usort() to sort an array by a user-defined function. That function could compare the ename fields. Then it's just a simple transformation. Like:
usort($array, 'cmp_ename');
function cmp_ename($a, $b) {
return strcmp($a['ename'], $b['ename']);
}
and then:
$output = array();
foreach ($array as $v) {
$ename = $v['ename'];
unset($v['ename']);
$output[] = array($ename => $v);
}
$outputarray = array();
foreach($inputarray as $value) {
$outputarray[] = array($value['ename'] => $value);
}
would accomplish what your examples seem to indicate (aside from the fact that your 'result' example has multiple things all with key 0... which isn't valid. I'm assuming you meant to number them 0,1,2 et cetera). However, I have to wonder what benefit you're getting from this, since all it appears to be doing is adding another dimension that serves no purpose. Perhaps you could clarify your example if there are other things to take into account?
$outputarray = array();
foreach($inputarray as &$value) {
$outputarray[][$value['ename']] = $value;
unset($value['ename']);
} unset($value);
I'm guessing that this is what you're asking for:
function array_group_by($input, $field) {
$out = array();
foreach ($input as $row) {
if (!isset($out[$row[$field]])) {
$out[$row[$field]] = array();
}
$out[$row[$field]][] = $row;
}
return $out;
}
And usage:
var_dump(array_group_by($input, 'ename'));
philfreo was right but he was also off a little. with his code every time you encounter an array element with an ['ename'] the same as one you've already gone through it will overwrite the data from the previous element with the same ['ename']
you might want to do something like this:
$output = array();
foreach ($YOURARRAY as $value) {
$output[$value['ename']][] = $value;
}
var_dump($output); // to check out what you get

Categories