SUM associative Array index dynamically on PHP - php

I have a result PHP array like this
$listResult = array(
0 => array(
0 => 1,
1 => 15,
2 => 4,
3 => 52
),
1 => array(
0 => 2,
1 => 0,
2 => 3,
3 => 2
),
2 => array(
0 => 3,
1 => 5,
2 => 9,
3 => 1
),
3 => array(
0 => 4,
1 => 10,
2 => 2,
3 => 5
),
4 => array(
0 => 1,
1 => 1,
2 => 2,
3 => 3
));
How to sum each keys? The result should be like this:
$sumResult = array(
0 => 11,
1 => 31,
2 => 20,
3 => 63
);
Already search in stackoverflow but the answer required key, in this case I just want to sum each index dynamically without a key. Sorry if my english is bad.

Use array_column() to get an array of all the elements with the same key, and array_sum() to sum them.
$sumResult = [];
foreach (array_keys($listResult[0]) as $key) {
$sumResult[$key] = array_sum(array_column($listResult, $key));
}

Related

How to yield value with the key?

How to set the key for yielded value? Can the generator have the key as well as array does?
I can easily name keys when returning arrays. It's very useful for PhpUnit dataProviders:
$array = [
'key' => ['value',1,2,3],
'here' => ['a',4,5,6],
'there' => ['b',7,8,9],
];
foreach( $array as $key => $value ){
echo $key."\t=>\t".var_export($value, true)."\n\n\n";
}
but can I do the same using generators?
e.g., how to change the following code?:
function hi()
{
yield ['value',1,2,3];
yield ['a',4,5,6];
yield ['b',7,8,9];
}
$array = hi();
foreach( $array as $key => $value ){
echo $key."\t=>\t".var_export($value, true)."\n\n\n";
}
Currently, the output is:
0 => array (
0 => 'value',
1 => 1,
2 => 2,
3 => 3,
)
1 => array (
0 => 'a',
1 => 4,
2 => 5,
3 => 6,
)
2 => array (
0 => 'b',
1 => 7,
2 => 8,
3 => 9,
)
How can I set the mindful keys for yielded values?
It is easy, yield has documented ability to use keys:
https://www.php.net/manual/en/language.generators.syntax.php
function hi()
{
yield 'key' => ['value',1,2,3];
yield 'here' => ['a',4,5,6];
yield 'there' => ['b',7,8,9];
}
$array = hi();
foreach( $array as $key => $value ){
echo $key."\t=>\t".var_export($value, true)."\n\n\n";
}
The output will have keys, as well as an array does:
key => [
0 => 'value',
1 => 1,
2 => 2,
3 => 3,
]
here => [
0 => 'a',
1 => 4,
2 => 5,
3 => 6,
]
there => [
0 => 'b',
1 => 7,
2 => 8,
3 => 9,
]

Transpose a multidimensional associative array into a multidimensional indexed array sorted against and an external associative key

I need to transpose a multidimensional associative array into a multidimensional indexed array sorted against and an external associative key. In the example below, I need a way to get from the 'input' to the 'expected output'.
I've tried array_match(), array_intersect() but I think I'm missing something. There must be an elegant solution to this but I cannot figure it out.
//Input
$array = array(
array('Volvo' => 22, 'BMW' => 13, 'Saab' => 5, 'Land Rover' => 11),
array('Nissan' => 10, 'Saab' => 4),
array('Land Rover' => 22, 'BMW' => 9, 'Nissan' => 2, 'Ford' => 17)
//...
);
//Expected output
$array_cars = array( // sorted list of unique car names
0 => 'BMW',
1 => 'Ford',
2 => 'Land Rover',
3 => 'Nissan',
4 => 'Saab',
5 => 'Volvo'
//...
);
$compiled_data = array( // 2D matrix, columns: $array, rows: $array_car
array(0 => 13, 2 => 9), // 'BMW'
array(2 => 17), // 'Ford'
array(0 => 11, 2 => 22), // 'Land Rover'
array(1 => 10, 2 => 2), // 'Nissan'
array(0 => 5, 1 => 4), // 'Saab'
array(1 => 22) // 'Volvo'
//...
);
Probably the simplest thing is to just iterate over all the values, sorting them into a car indexed array. You can then use ksort to sort the data:
$output = array();
foreach ($array as $key => $a) {
foreach ($a as $car => $v) {
$output[$car][$key] = $v;
}
}
ksort($output);
$array_cars = array_keys($output);
$compiled_data = array_values($output);
var_export($array_cars);
var_export($compiled_data);
Output:
array (
0 => 'BMW',
1 => 'Ford',
2 => 'Land Rover',
3 => 'Nissan',
4 => 'Saab',
5 => 'Volvo',
)
array (
0 =>
array (
0 => 13,
2 => 9,
),
1 =>
array (
2 => 17,
),
2 =>
array (
0 => 11,
2 => 22,
),
3 =>
array (
1 => 10,
2 => 2,
),
4 =>
array (
0 => 5,
1 => 4,
),
5 =>
array (
0 => 22,
),
)
Demo on 3v4l.org

PHP Multidimensional Array Sort & Trim

I have the array below. I do not know how I can sort secondary array so elements with highest value gets to be first and I want to trim if the array length is more than 20 elements. I want first dimension to be sorted by alphabetical, secondary dimension to be sorted by values and if there are more than 20 entries, I want only first 20 highest value.
(
[a] => Array
(
[option1] => 2
[option2] => 3
[option3] => 1
[option4] => 7
[option5] => 8
[option6] => 3
[option7] => 2
[option8] => 32
[option9] => 35
[option10] => 33
[option11] => 32
[option12] => 35
[option13] => 37
[option14] => 3
[option15] => 39
[option16] => 4
[option17] => 36
[option18] => 31
[option19] => 12
[option20] => 35
[option21] => 3
[option22] => 32
[option23] => 31
)
[b] => Array
(
[option16] => 4
[option17] => 36
[option18] => 31
[option19] => 12
)
Php has everything for you!
<?php
$array = array(
'b' => array(
'option1' => 33,
'option2' => 12,
'option3' => 17,
'option4' => 44,
'option5' => 543,
'option6' => 56,
'option7' => 8,
'option8' => 0,
'option9' => -10,
'option10' => 234,
'option11' => 67,
'option12' => 99,
'option13' => 3363,
'option14' => 912,
'option15' => 51,
'option16' => 42,
'option17' => 105,
'option18' => 80,
'option19' => 44,
'option20' => 0,
'option21' => 15,
),
'a' => array(
'option1' => 88,
'option2' => 0,
'option3' => -23,
'option4' => 16,
'option5' => 76,
),
);
// sorts array keys alphabetically
ksort($array, SORT_NATURAL);
// iterrate each key (a or b etc.) => value (value is assoc array of options) pair
foreach ($array as $k => &$v) {
// reverse sort (from max to min) options by its value
// with preserve keys
arsort($v);
// cut options array to max 20 element
$v = array_slice($v, 0, 20);
}
echo '<pre>' . print_r($array, 1) . '</pre>';
Online runnable.

remove empty array from multidimensional array

I have the following array
$cal = array(
0 => array(
0 => array(
0 => '*',
1 => 2,
2 => 3,
) ,
1 => array(
0 => 6,
1 => 7,
2 => 8,
3 => 9,
4 => 10,
) ,
2 => array(
0 => '*',
1 => '*',
2 => 15,
3 => '*',
4 => 17,
) ,
3 => array(
0 => 20,
1 => 21,
2 => 22,
3 => 23,
4 => 24,
) ,
4 => array(
0 => 27,
1 => 28,
2 => 29,
3 => 30,
4 => 31,
) ,
) ,
1 => array(
0 => array() ,
1 => array(
0 => 3,
1 => 4,
2 => 5,
3 => '*',
4 => 7,
) ,
2 => array(
0 => 10,
1 => 11,
2 => 12,
3 => 13,
4 => 14,
) ,
3 => array(
0 => 17,
1 => 18,
2 => 19,
3 => 20,
4 => 21,
) ,
4 => array(
0 => 24,
1 => 25,
2 => 26,
3 => 27,
4 => 28,
) ,
) ,
2 => array(
0 => array() ,
1 => array(
0 => 3,
1 => 4,
2 => 5,
3 => 6,
4 => '*',
) ,
2 => array(
0 => 10,
1 => 11,
2 => 12,
3 => 13,
4 => 14,
) ,
3 => array(
0 => 17,
1 => 18,
2 => 19,
3 => 20,
4 => 21,
) ,
4 => array(
0 => 24,
1 => 25,
2 => 26,
3 => 27,
4 => 28,
) ,
5 => array(
0 => 31,
) ,
) ,
3 => array(
0 => array(
0 => 1,
1 => 2,
2 => 3,
3 => 4,
) ,
1 => array(
0 => 7,
1 => 8,
2 => 9,
3 => 10,
4 => 11,
) ,
2 => array(
0 => 14,
1 => 15,
2 => 16,
3 => 17,
4 => 18,
) ,
3 => array(
0 => 21,
1 => 22,
2 => 23,
3 => 24,
4 => 25,
) ,
4 => array(
0 => 28,
1 => 29,
2 => 30,
) ,
) ,
4 => array(
0 => array(
0 => 1,
1 => 2,
) ,
1 => array(
0 => '*',
1 => '*',
2 => '*',
3 => 8,
4 => 9,
) ,
2 => array(
0 => 12,
1 => 13,
2 => 14,
3 => 15,
4 => 16,
) ,
3 => array(
0 => 19,
1 => 20,
2 => 21,
3 => 22,
4 => 23,
) ,
4 => array(
0 => 26,
1 => 27,
2 => 28,
3 => 29,
4 => 30,
) ,
) ,
5 => array(
0 => array() ,
1 => array(
0 => 3,
1 => '*',
2 => 5,
3 => 6,
) ,
2 => array(
0 => 9,
1 => 10,
2 => 11,
3 => 12,
4 => '*',
) ,
3 => array(
0 => 16,
1 => 17,
2 => 18,
3 => 19,
4 => 20,
) ,
4 => array(
0 => 23,
1 => 24,
2 => 25,
3 => 26,
4 => 27,
) ,
5 => array(
0 => 30,
) ,
) ,
6 => array(
0 => array(
0 => 1,
1 => 2,
2 => 3,
3 => 4,
) ,
1 => array(
0 => 7,
1 => 8,
2 => 9,
3 => 10,
4 => 11,
) ,
2 => array(
0 => 14,
1 => 15,
2 => 16,
3 => 17,
4 => 18,
) ,
3 => array(
0 => 21,
1 => 22,
2 => 23,
3 => 24,
4 => 25,
) ,
4 => array(
0 => 28,
1 => 29,
2 => 30,
3 => 31,
) ,
) ,
7 => array(
0 => array(
0 => 1,
) ,
1 => array(
0 => 4,
1 => 5,
2 => 6,
3 => 7,
4 => 8,
) ,
2 => array(
0 => 11,
1 => 12,
2 => 13,
3 => 14,
4 => 15,
) ,
3 => array(
0 => 18,
1 => 19,
2 => 20,
3 => 21,
4 => 22,
) ,
4 => array(
0 => 25,
1 => 26,
2 => 27,
3 => 28,
4 => 29,
) ,
5 => array() ,
) ,
8 => array(
0 => array(
0 => 1,
1 => 2,
2 => 3,
3 => 4,
4 => 5,
) ,
1 => array(
0 => 8,
1 => 9,
2 => 10,
3 => 11,
4 => 12,
) ,
2 => array(
0 => 15,
1 => 16,
2 => 17,
3 => 18,
4 => 19,
) ,
3 => array(
0 => 22,
1 => 23,
2 => 24,
3 => 25,
4 => 26,
) ,
4 => array(
0 => 29,
1 => 30,
) ,
) ,
9 => array(
0 => array(
0 => 1,
1 => 2,
2 => 3,
) ,
1 => array(
0 => '*',
1 => '*',
2 => '*',
3 => '*',
4 => '*',
) ,
2 => array(
0 => '*',
1 => '*',
2 => '*',
3 => '*',
4 => '*',
) ,
3 => array(
0 => 20,
1 => 21,
2 => 22,
3 => 23,
4 => 24,
) ,
4 => array(
0 => 27,
1 => 28,
2 => 29,
3 => 30,
4 => 31,
) ,
) ,
10 => array(
0 => array() ,
1 => array(
0 => 3,
1 => '*',
2 => 5,
3 => 6,
4 => 7,
) ,
2 => array(
0 => 10,
1 => 11,
2 => 12,
3 => 13,
4 => 14,
) ,
3 => array(
0 => 17,
1 => 18,
2 => 19,
3 => 20,
4 => 21,
) ,
4 => array(
0 => 24,
1 => 25,
2 => 26,
3 => '*',
4 => 28,
) ,
5 => array() ,
) ,
11 => array(
0 => array(
0 => '*',
1 => 2,
2 => 3,
3 => 4,
4 => '*',
) ,
1 => array(
0 => 8,
1 => 9,
2 => 10,
3 => 11,
4 => 12,
) ,
2 => array(
0 => 15,
1 => 16,
2 => 17,
3 => 18,
4 => 19,
) ,
3 => array(
0 => 22,
1 => 23,
2 => 24,
3 => 25,
4 => 26,
) ,
4 => array(
0 => 29,
1 => 30,
2 => 31,
) ,
) ,
)
I'm trying to remove empty array from its parent using the following code:
for($m = 0; $m < count($cal); $m++){
for($w = 0; $w < count($cal[$m]); $w++){
if(empty($cal[$m][$w])){
array_shift($cal[$m]);
}
}
}
the result is (please see index 10)
10 => array(
0 => array(
0 => 10,
1 => 11,
2 => 12,
3 => 13,
4 => 14,
) ,
1 => array(
0 => 17,
1 => 18,
2 => 19,
3 => 20,
4 => 21,
) ,
2 => array(
0 => 24,
1 => 25,
2 => 26,
3 => '*',
4 => 28,
) ,
3 => array() ,
) ,
what i expect is remove the first and the last, it is instead remove first and second array and leave the last array still there. any idea?
Try to use array_filter() instead since array_shift() just takes care of the first element:
foreach ($cal as &$value) {
$value = array_filter($value);
}
You can use a simple recursive function to traverse each like this:
<?php
function removeEmpties(&$array)
{
foreach($array as $key=>$val)
{
if(count($val)==0)
{
unset($array[$key]);
}
else
{
removeEmpties($val);
}
}
}
$yourArray=array( ... etc );
removeEmpties($yourArray);
?>
try this code:
foreach ($cal as &$arr)
{
$arr = array_filter($arr);
}
$cal = array_filter($cal);
Use unset($cal[$m][$w]) instead of array_shift($cal[$m]).
This will result in
10 => array(
1 => array(
0 => 3,
1 => '*',
2 => 5,
3 => 6,
4 => 7,
) ,
2 => array(
0 => 10,
1 => 11,
2 => 12,
3 => 13,
4 => 14,
) ,
3 => array(
0 => 17,
1 => 18,
2 => 19,
3 => 20,
4 => 21,
) ,
4 => array(
0 => 24,
1 => 25,
2 => 26,
3 => '*',
4 => 28,
) ,
) ,
Notice the key [0] is no longer present

Elegant way to convert associative array into an indexed one [duplicate]

This question already has answers here:
Transposing multidimensional arrays in PHP
(12 answers)
Closed 1 year ago.
Having an associative array like
$myarray = array (
'user' => array (
2 => 'john',
5 => 'done',
21 => 'foo'
),
'city' => array (
2 => 'london',
5 => 'buenos aires',
21 => 'paris',
),
'age' => array (
2 => 24,
5 => 38,
21 => 16
)
...
);
EDITED
Assuming I don't know how many keys this array has, nor the keys themselves (they could be whatever) The above is just an example
Is there any elegant way (using built-in functions and not loops) to convert it into
$result = array(
array(
'user',
'city',
'age'
...
),
array(
'john',
'london',
24
...
),
array(
'done',
'buenos aires',
38
...
),
array(
'foo',
'paris',
16
...
)
);
As a side question: how to obtain this too (in a similar elegant way)
$result = array(
array(
'row',
'user',
'city',
'age'
...
),
array(
2,
'john',
'london',
24
...
),
array(
5,
'done',
'buenos aires',
38
...
),
array(
21,
'foo',
'paris',
16
...
)
);
Note that both of these operations are basically the transpose of your original array.
All of this is strongly adapted from this answer (consider upvoting it!).
helper
First we need a helper function, which keeps the row headers as the keys in the associative array:
function flipArrayKeys($arr) {
$out = array('row' => array_keys($arr));
foreach ($arr as $key => $subarr) {
foreach ($subarr as $subkey => $subvalue) {
$out[$subkey][] = $subvalue;
}
}
return $out;
}
flipArrayKeys($myarray) gives:
array (
'row' =>
array (
0 => 'user',
1 => 'city',
2 => 'age',
),
2 =>
array (
0 => 'john',
1 => 'london',
2 => 24,
),
5 =>
array (
0 => 'done',
1 => 'buenos aires',
2 => 38,
),
21 =>
array (
0 => 'foo',
1 => 'paris',
2 => 16,
),
)
part 1
$result = array_values(flipArrayKeys($myarray));
and now result looks like:
array (
0 =>
array (
0 => 'user',
1 => 'city',
2 => 'age',
),
1 =>
array (
0 => 'john',
1 => 'london',
2 => 24,
),
2 =>
array (
0 => 'done',
1 => 'buenos aires',
2 => 38,
),
3 =>
array (
0 => 'foo',
1 => 'paris',
2 => 16,
),
)
This part can also be done using transpose from this answer:
$result = transpose($myarray);
array_unshift($result, array_keys($myarray));
part 2
function flipArrayWithHeadings($arr) {
$out = flipArrayKeys($arr);
foreach (array_keys($out) as $key) {
array_unshift($out[$key],$key);
}
return array_values($out);
}
So flipArrayWithHeadings($myarray) looks like:
array (
0 =>
array (
0 => 'row',
1 => 'user',
2 => 'city',
3 => 'age',
),
1 =>
array (
0 => 2,
1 => 'john',
2 => 'london',
3 => 24,
),
2 =>
array (
0 => 5,
1 => 'done',
2 => 'buenos aires',
3 => 38,
),
3 =>
array (
0 => 21,
1 => 'foo',
2 => 'paris',
3 => 16,
),
)
Use the array_values function as:
$result = array(array_values($myarray['user']),
array_values($myarray['city']),
array_values($myarray['age']));
For the 2nd part of the question you can do:
$result2 = array_keys($myarray);
foreach(array_keys($myarray['user']) as $k) {
$result2[] = array($k, $myarray['user'][$k], $myarray['city'][$k], $myarray['age'][$k]);
}

Categories