Sum of duplicate key values array in PHP [duplicate] - php

This question already has answers here:
How to sum all column values in multi-dimensional array?
(20 answers)
Closed 9 months ago.
I have an array with duplicate key values. How can I sum all duplicate array key values in another new array?
$array = Array (
"0" => Array ( "2" => 123 ),
"1" => Array ( "4" => 45 ),
"2" => Array ( "3" => 12 ),
"3" => Array ( "5" => 2 ),
"4" => Array ( "2" => 12 ),
"5" => Array ( "4" => 21 ),
"6" => Array ( "2" => 12 ),
"7" => Array ( "3" => 21 ),
"8" => Array ( "2" => 12 ),
"9" => Array ( "3" => 21 ),
"10" => Array ( "2" => 2 ),
"11" => Array ( "4" => 2 ),
"12" => Array ( "2" => 2 ),
"13" => Array ( "4" => 2 ),
"14" => Array ( "3" => 12 ),
"15" => Array ( "4" => 12 ),
"16" => Array ( "2" => 12 ),
"17" => Array ( "2" => 12 ),
"18" => Array ( "4" => 12 ),
"19" => Array ( "3" => 12 ),
"20" => Array ( "2" => 15 ),
"21" => Array ( "4" => 21 ),
);
Output will looks like
$newArray = Array
(
[2] => 202
[3] => 78
[4] => 115
[5] => 2
)

You can use array_sum and array_column to get the sums of each.
First we have to get all the keys then sum them with array_sum and array_column.
$arr = Array (
"0" => Array ( "2" => 123 ),
"1" => Array ( "4" => 45 ),
"2" => Array ( "3" => 12 ),
"3" => Array ( "5" => 2 ),
"4" => Array ( "2" => 12 ),
"5" => Array ( "4" => 21 ),
"6" => Array ( "2" => 12 ),
"7" => Array ( "3" => 21 ),
"8" => Array ( "2" => 12 ),
"9" => Array ( "3" => 21 ),
"10" => Array ( "2" => 2 ),
"11" => Array ( "4" => 2 ),
"12" => Array ( "2" => 2 ),
"13" => Array ( "4" => 2 ),
"14" => Array ( "3" => 12 ),
"15" => Array ( "4" => 12 ),
"16" => Array ( "2" => 12 ),
"17" => Array ( "2" => 12 ),
"18" => Array ( "4" => 12 ),
"19" => Array ( "3" => 12 ),
"20" => Array ( "2" => 15 ),
"21" => Array ( "4" => 21 ),
);
// find all subarray keys (2,3,4,5)
foreach($arr as $subarr){
$keys[] = key($subarr);
}
// remove duplicate keys
$keys = array_unique($keys);
// sum values with same key from $arr and save to $sums
foreach($keys as $key){
$sums[$key] = array_sum(array_column($arr,$key));
}
var_dump($sums);
https://3v4l.org/F3RJr
The code can be made shorter like this:
foreach($arr as $subarr){
$key = key($subarr);
if(!isset($sums[$key])){
$sums[$key] = array_sum(array_column($arr,$key));
}
}
var_dump($sums);
but I'm not sure it's faster. Maybe...

You can use array_walk_recursive()
$result = [];
array_walk_recursive($array, function($v, $k) use (&$result) {
if (!isset($result[$k])) {
$result[$k] = $v;
} else {
$result[$k] += $v;
}
});
print_r($result);

Check the below code.
$output = array();
$keyarray = array();
foreach($arr as $key => $val){
if(is_array($val)){
$key = key($val);
if(in_array($key,$keyarray)) {
$output[$key] = $output[$key]+$val[$key];
} else {
$keyarray[] = $key;
$output[$key] = $val[$key];
}
}
}
print_r($output);
print_r($output); will give you the expected result.

Related

PHP Array manipulation need tips

I have arrays in one submission, please see below details:
array(5) {
["ambition_id"]=>
array(2) {
[55]=> string(2) "55"
[60]=> string(2) "60"
}
["target"]=>
array(1) {
[0]=> string(8) "target 1"
[1]=> string(8) "target 2"
}
["strides"]=>
array(1) {
[0]=> string(1) "1"
[1]=> string(1) "1"
}
["date"]=>
array(1) {
[0]=> string(10) "2017-02-08"
[1]=> string(10) "2017-03-08"
}
["frequency"]=>
array(1) {
[0]=> string(1) "1"
[1]=> string(1) "2"
}
}
Actually, I have two tables in mysql, 'ambition' and 'target'. Ambition is a group of targets ('ambition_id' is foreign key in 'target' table). That array will be stored in 'target' table. That's why there is an 'ambition_id'
I've tried many times but failed (using foreach), now I need someone who can give me a help.
By brute force, It's easy! I solved it already but I need "more advanced" array manipulation.
How can I come up into this?
array(2) {
[0] => array('ambition_id' => 55,
'target' => 'target 1',
'strides' => 1,
'date' => '2017-02-08',
'frequency' => 1
),
[1] => array('ambition_id' => 60,
'target' => 'target 2',
'strides' => 2,
'date' => '2017-03-08',
'frequency' => 2)
}
Please do help, many thanks!
You have to pivot your data:
$data = array (
"ambition_id" =>
array (
55 => "55",
60 => "60"
),
"target" =>
array (
0 => "target 1",
1 => "target 2"
),
"strides" =>
array (
0 => "1",
1 => "1"
),
"date" =>
array (
0 => "2017-02-08",
1 => "2017-03-08"
),
"frequency" =>
array (
0 => "1",
1 => "2"
)
);
// pivot data
$pivot = array();
foreach ($data as $datum => $values) {
$value_index = 0;
foreach ($values as $value) {
$pivot[$value_index][$datum] = $value;
$value_index++;
}
}
print_r($pivot);
This assumes you only have two levels of data and that the data is well behaved.
Not the best answer, but it solves your problem
<?php
$array = [
"ambition_id" =>
[
55 => "55",
60 => "60"
],
"target" =>
[
0 => "target 1",
1 => "target 2"
],
"strides" =>
[
0 => "1",
1 => "1"
],
"date" =>
[
0 => "2017-02-08",
1 => "2017-03-08"
],
"frequency" =>
[
0 => "1",
1 => "2"
],
];
$result = array();
foreach ($array as $k => $v) {
foreach ($v as $kk => $vv) {
if ($k == "ambition_id") {
$result[] = array($k => $vv);
} else {
$result[$kk][$k] = $vv;
}
}
}
Here is the test https://3v4l.org/UdHH8
Just use loop the array and user array_values to re-index the loop the inner array and store it into new array like below .
<?php
$new_array =array();
foreach($array as $key1=>$row1 )
{
$ss =array_values($row1);
foreach($ss as $key2=>$row2)
{
$new_array[$key2][$key1]=$row2;
}
}
echo "<pre>";
print_r($new_array);
?>
Output :
Array
(
[0] => Array
(
[ambition_id] => 55
[target] => target 1
[strides] => 1
[date] => 2017-02-08
[frequency] => 1
)
[1] => Array
(
[ambition_id] => 60
[target] => target 2
[strides] => 1
[date] => 2017-03-08
[frequency] => 2
)
)

Replace multidimensional array that has the same key values [duplicate]

This question already has answers here:
Merge two 2d arrays by shared column value
(6 answers)
Closed 2 months ago.
I have this array that I have to replace the values according to their id. below is the Original Array:
[
0 => [
"id" => "70"
"color" => "red"
]
1 => [
"id" => "65"
"color" => "blue"
]
2 => [
"id" => "66"
"color" => "black"
]
3 => [
"id" => "73"
"color" => "red"
]
]
And this is the array that I need to insert and replace the array that has the same id in the original array:
0 => [
"id" => "65"
"color" => "white"
]
1 => [
"id" => "66"
"color" => "gold"
]
]
What I am trying to achieve is something like this:
[
0 => [
"id" => "70"
"color" => "red"
]
1 => [
"id" => "65"
"color" => "white"
]
2 => [
"id" => "66"
"color" => "gold"
]
3 => [
"id" => "73"
"color" => "red"
]
]
Simple solution with array_column and array_walk functions:
// $arr1 is the original array
// $arr2 is the replacing array
$colours = array_column($arr2, "color", "id");
array_walk($arr1, function(&$v) use($colours){
if (array_key_exists($v["id"],$colours)) {
$v["color"] = $colours[$v["id"]];
}
});
print_r($arr1);
The output:
Array
(
[0] => Array
(
[id] => 70
[color] => red
)
[1] => Array
(
[id] => 65
[color] => white
)
[2] => Array
(
[id] => 66
[color] => gold
)
[3] => Array
(
[id] => 73
[color] => red
)
)
http://php.net/manual/ru/function.array-column.php
http://php.net/manual/ru/function.array-walk.php
Try this code:
<?php
$original = [
0 => [
"id" => "70",
"color" => "red" ,
],
1 => [
"id" => "65",
"color" => "blue",
],
2 => [
"id" => "66",
"color" => "black",
],
3 => [
"id" => "73",
"color" => "red",
]
];
$toReplace = [0 => [
"id" => "65",
"color" => "white" ,
],
1 => [
"id" => "66",
"color" => "gold",
]
];
function getColorByKey($key, $toReplace)
{
$result = null;
foreach($toReplace as $k => $value)
{
if($value['id'] == $key)
$result = $value['color'];
}
return $result;
}
foreach($original as $key => $value)
{
$newColor = getColorByKey($value['id'], $toReplace);
$original[$key]['color'] = $newColor !== null ? $newColor : $original[$key]['color'];
}
var_dump($original);
Output of var_dump:
array(4) {
[0]=>
array(2) {
["id"]=>
string(2) "70"
["color"]=>
string(3) "red"
}
[1]=>
array(2) {
["id"]=>
string(2) "65"
["color"]=>
string(5) "white"
}
[2]=>
array(2) {
["id"]=>
string(2) "66"
["color"]=>
string(4) "gold"
}
[3]=>
array(2) {
["id"]=>
string(2) "73"
["color"]=>
string(3) "red"
}
}
There is a function getColorByKey($key, $toReplace) which is used in foreach loop, where $key is id index, and $toReplace is your second array.
// $array1 = original array
// $array2 = second array
foreach ($array1 as $key1 => $value)
{
$new[$value['id']] = $key1;
}
foreach ($array2 as $value)
{
if (array_key_exists($value['id'], $new))
{
$key2 = $new[$value['id']];
$array1[$key2]['color'] = $value['color'];
}
else
{
$array1[] = array('id' => $value['id'], 'color' => $value['color']);
// if this color not present, then it adds this to the original array
}
}
echo '<pre>'; print_r($array1);
Output:
Array
(
[0] => Array
(
[id] => 70
[color] => red
)
[1] => Array
(
[id] => 65
[color] => white
)
[2] => Array
(
[id] => 66
[color] => gold
)
[3] => Array
(
[id] => 73
[color] => red
)
)

how to flatten a multidimensional array in php [duplicate]

This question already has answers here:
How to Flatten a Multidimensional Array?
(31 answers)
Closed 1 year ago.
This is my array and i want 60 , 20, 39, 70,12, 29,31,72,59 in a single array. one-dimensional array.
$marks = array(
"abc" => array(
"a" => 60,
"b" => 20,
"c" => 39
),
"def" => array(
"a" => 70,
"b" => 12,
"c" => 29
),
"xyz" => array(
"a" => 31,
"b" => 72,
"c" => 59
)
)Íž
my try was
foreach($marks as $name=>$score)
{
foreach($score as $subject=>$number)
{
$array[]= $number;
}
}
But when i am printing this array it again generate three array.
on print_r($array); its showing this output.
Array ( [0] => 60 [1] => 20 [2] => 39 ) Array ( [0] => 60 [1] => 20 [2] => 39 [3] => 70 [4] => 12 [5] => 29 ) Array ( [0] => 60 [1] => 20 [2] => 39 [3] => 70 [4] => 12 [5] => 29 [6] => 31 [7] => 72 [8] => 59 )
is there any method to get only last array from the above array.or any other solution.
Try this to flatten the array:
<?php
$marks = array(
"abc" => array(
"a" => 60,
"b" => 20,
"c" => 39
),
"def" => array(
"a" => 70,
"b" => 12,
"c" => 29
),
"xyz" => array(
"a" => 31,
"b" => 72,
"c" => 59
)
);
function array_values_recursive($array)
{
$arrayValues = array();
foreach ($array as $value)
{
if (is_scalar($value) OR is_resource($value))
{
$arrayValues[] = $value;
}
elseif (is_array($value))
{
$arrayValues = array_merge($arrayValues, array_values_recursive($value));
}
}
return $arrayValues;
}
var_dump(array_values_recursive($marks));
Output:
array(9) { [0]=> int(60) [1]=> int(20) [2]=> int(39) [3]=> int(70) [4]=> int(12) [5]=> int(29) [6]=> int(31) [7]=> int(72) [8]=> int(59) }
This custom function was taken from: http://php.net/manual/en/function.array-values.php
you can do in either traditional way i.e. foreach loop and also can use iterator. have a look on below solution:
1) using foreach loop and array_merge function
$marks = array(
"abc" => array(
"a" => 60,
"b" => 20,
"c" => 39
),
"def" => array(
"a" => 70,
"b" => 12,
"c" => 29
),
"xyz" => array(
"a" => 31,
"b" => 72,
"c" => 59
)
);
$new_array = array();
foreach ($marks as $mark) {
$new_array = array_merge($new_array, array_values($mark));
}
print_r($new_array);
2) using ArrayIterator:
$new_array = array();
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($marks));
foreach ($iterator as $key => $value) {
$new_array[] = $value;
}
print_r($new_array);
In both solution Output will be:
Array
(
[0] => 60
[1] => 20
[2] => 39
[3] => 70
[4] => 12
[5] => 29
[6] => 31
[7] => 72
[8] => 59
)
Because you're dumping $array inside the first foreach loop :)
Your sound like you may be declare your $array in for loop ,if you do so you will get three arrays.So declare outside of for loop will be get single array
$array = array(); //correct
foreach($marks as $name=>$score)
{
//$array = array(); //incorrect
foreach($score as $subject=>$number)
{
$array[]= $number;
}
}
var_dump($array);
foreach($marks as $name=>$score)
{
foreach($score as $subject=>$number)
{
$array[]= $number;
}
}

Prepend to multidimensional associative array

I'm PHP beginner and have a question:
I have a multidimensional associative array:
array(
"X" => array( "x1" => "1", "x2" => "2", "x3" => "3" ),
"Y" => array( "y1" => "1", "y2" => "2", "y3" => "3" ),
"Z" => array( "z1" => "1", "z2" => "2", "z3" => "3" )
)
and need to prepend "" => "" to every element X, Y, Z, so then it will be:
array(
"X" => array( "" => "", "x1" => "1", "x2" => "2", "x3" => "3" ),
"Y" => array( "" => "", "y1" => "1", "y2" => "2", "y3" => "3" ),
"Z" => array( "" => "", "z1" => "1", "z2" => "2", "z3" => "3" )
)
X, Y, Z names are often changed, so I need to get a key name first and then add new value.
I think of using foreach somehow. I'm trying it, but can achieve it.
Thanks
<?php
$temp = array(
"X" => array( "x1" => "1", "x2" => "2", "x3" => "3" ),
"Y" => array( "y1" => "1", "y2" => "2", "y3" => "3" ),
"Z" => array( "z1" => "1", "z2" => "2", "z3" => "3" )
);
$you_array = array();
foreach($temp as $k=>$v){
$v = array_merge([""=>""],$v);
$you_array[$k] = $v;
}
print_r($you_array);
?>
check the following code:
<?php
$temp = array(
"X" => array( "x1" => "1", "x2" => "2", "x3" => "3" ),
"Y" => array( "y1" => "1", "y2" => "2", "y3" => "3" ),
"Z" => array( "z1" => "1", "z2" => "2", "z3" => "3" )
);
$you_array = array();
foreach($temp as $k=>$v){
array_unshift($v, " ");
$you_array[$k] = $v;
}
print_r($you_array);
?>
Out put :
Array (
[X] => Array ( [0] => [x1] => 1 [x2] => 2 [x3] => 3 )
[Y] => Array ( [0] => [y1] => 1 [y2] => 2 [y3] => 3 )
[Z] => Array ( [0] => [z1] => 1 [z2] => 2 [z3] => 3 )
)
You can use array_unshift to add new elements to an array.
As you already mentioned, create a foreach loop and add your new elements to each sub-array:
$new = array("new_key" => "");
foreach ($yourArray as $key => $value)
array_unshift($yourArray[$key], $new);
Be careful: Your new element needs a key value. An empty key (like you mentioned) is not possible. If you just add a new element without a key array("") it will be added with a numerical key (0 => ""). Existing numerical keys will be modified to start counting from zero.
I think this is what you are looking for
[akshay#localhost tmp]$ cat test.php
<?php
$array=array(
"X" => array( "x1" => "1", "x2" => "2", "x3" => "3" ),
"Y" => array( "y1" => "1", "y2" => "2", "y3" => "3" ),
"Z" => array( "z1" => "1", "z2" => "2", "z3" => "3" )
);
// Input
print_r($array);
// & reference
foreach($array as &$sub_array)
{
$sub_array = array(""=>"")+$sub_array;
}
// Output
print_r($array);
?>
Output
[akshay#localhost tmp]$ php test.php
Array
(
[X] => Array
(
[x1] => 1
[x2] => 2
[x3] => 3
)
[Y] => Array
(
[y1] => 1
[y2] => 2
[y3] => 3
)
[Z] => Array
(
[z1] => 1
[z2] => 2
[z3] => 3
)
)
Array
(
[X] => Array
(
[] =>
[x1] => 1
[x2] => 2
[x3] => 3
)
[Y] => Array
(
[] =>
[y1] => 1
[y2] => 2
[y3] => 3
)
[Z] => Array
(
[] =>
[z1] => 1
[z2] => 2
[z3] => 3
)
)

Regular expression, filtering expected data from an array like ":key{value}"

Example:
$match_check = "(?'txt'(?<=:txt{)([^}]+)(?=}))|(?'reg'(?<=:reg{)([^}]+)(?=}))";
$route_from_value = ':txt{resultxt}:txt{test}:reg{/^[a-zA-Z]*$/}:reg{regexresult}';
preg_match_all('/'.$match_check.'/', $route_from_value, $get_matchers_check);
var_dump($get_matchers_check);
And result for given question are:
array(7) {
[0] =>
array(4) {
[0] =>
string(8) "resultxt"
[1] =>
string(4) "test"
[2] =>
string(13) "/^[a-zA-Z]*$/"
[3] =>
string(11) "regexresult"
}
'txt' =>
array(4) {
[0] =>
string(8) "resultxt"
[1] =>
string(4) "test"
[2] =>
string(0) ""
[3] =>
string(0) ""
}
[1] =>
array(4) {
[0] =>
string(8) "resultxt"
[1] =>
string(4) "test"
[2] =>
string(0) ""
[3] =>
string(0) ""
}
[2] =>
array(4) {
[0] =>
string(8) "resultxt"
[1] =>
string(4) "test"
[2] =>
string(0) ""
[3] =>
string(0) ""
}
'reg' =>
array(4) {
[0] =>
string(0) ""
[1] =>
string(0) ""
[2] =>
string(13) "/^[a-zA-Z]*$/"
[3] =>
string(11) "regexresult"
}
[3] =>
array(4) {
[0] =>
string(0) ""
[1] =>
string(0) ""
[2] =>
string(13) "/^[a-zA-Z]*$/"
[3] =>
string(11) "regexresult"
}
[4] =>
array(4) {
[0] =>
string(0) ""
[1] =>
string(0) ""
[2] =>
string(13) "/^[a-zA-Z]*$/"
[3] =>
string(11) "regexresult"
}
}
But, expected result should be (how make it only with regexp?) or something simply:
'txt' =>
array(4) {
[0] =>
string(8) "resultxt"
},
'txt' =>
array(4) {
[0] =>
string(8) "resultxt"
}
'reg' =>
array(4) {
[0] =>
string(8) "/^[a-zA-Z]*$/"
}
'reg' =>
array(4) {
[0] =>
string(8) "regexresult"
}
The output of preg_match_all and preg_split function follows a format that doesn't match what you want.
What you can do is just do some post-processing on the output of preg_match_all to obtain the result (something like an array of ['key', 'value'] pair). Note that you should set the flag PREG_OFFSET_CAPTURE to obtain the index of the match for comparison. A capturing group that matches nothing will give index -1 or will not return an array that contains 2 elements.
By the way, you can remove some unnecessary capturing group from your regex.
"(?'txt'(?<=:txt{)[^}]+(?=}))|(?'reg'(?<=:reg{)[^}]+(?=}))"
Sample run:
$matches = null;
$returnValue = preg_match_all('/(?\'txt\'(?<=:txt{)[^}]+(?=}))|(?\'reg\'(?<=:reg{)[^}]+(?=}))/', ':txt{resultxt}:txt{test}:reg{/^[a-zA-Z]*$/}:reg{regexresult}', $matches, PREG_OFFSET_CAPTURE);
Output:
array (
0 =>
array (
0 =>
array (
0 => 'resultxt',
1 => 5,
),
1 =>
array (
0 => 'test',
1 => 19,
),
2 =>
array (
0 => '/^[a-zA-Z]*$/',
1 => 29,
),
3 =>
array (
0 => 'regexresult',
1 => 48,
),
),
'txt' =>
array (
0 =>
array (
0 => 'resultxt',
1 => 5,
),
1 =>
array (
0 => 'test',
1 => 19,
),
2 => // No match found, index -1
array (
0 => '',
1 => -1,
),
3 => // No match found, index -1
array (
0 => '',
1 => -1,
),
),
1 =>
array (
0 =>
array (
0 => 'resultxt',
1 => 5,
),
1 =>
array (
0 => 'test',
1 => 19,
),
2 =>
array (
0 => '',
1 => -1,
),
3 =>
array (
0 => '',
1 => -1,
),
),
'reg' =>
array (
0 => '', // No match found, not array of 2 elements [<matched text>, <index>]
1 => '', // No match found, not array of 2 elements [<matched text>, <index>]
2 =>
array (
0 => '/^[a-zA-Z]*$/',
1 => 29,
),
3 =>
array (
0 => 'regexresult',
1 => 48,
),
),
2 =>
array (
0 => '',
1 => '',
2 =>
array (
0 => '/^[a-zA-Z]*$/',
1 => 29,
),
3 =>
array (
0 => 'regexresult',
1 => 48,
),
),
)

Categories