How to average columns of data from multiple, flat arrays? - php

Let's say I have 4 arrays with the same amount of values in each:
$array1 = array(0, 7, 5, 0);
$array2 = array(2, 6, 10, 0);
$array3 = array(4, 8, 15, 10);
$array4 = array(6, 7, 20, 10);
I want to count the average for all 4 of these arrays for each index. So I should get something like this:
array(3, 7, 12.5, 5);

For more dynamically usage lets say for example 6 arrays or more, you can use this code:
$all_arrays = [
array(0, 7, 5, 0),
array(2, 6, 10, 0),
array(4, 8, 15, 10),
array(6, 7, 20, 10),
array(1, 2, 3, 4),
array(5, 6, 7, 8),
// more arrays
];
$each_array_count = count($all_arrays[0]); // 4
$all_arrays_count = count($all_arrays); // 6
$output = [];
for ($i = 0; $i < $each_array_count; $i++) {
for ($j=0; $j < $all_arrays_count; $j++) {
$output[$i] += $all_arrays[$j][$i] / $all_arrays_count;
}
}
echo "<pre>";
var_dump($output);
Output: (Demo)
Warning: Undefined array key 0 in /in/E783F on line 20
Warning: Undefined array key 1 in /in/E783F on line 20
Warning: Undefined array key 2 in /in/E783F on line 20
Warning: Undefined array key 3 in /in/E783F on line 20
<pre>array(4) {
[0]=>
float(3)
[1]=>
float(6)
[2]=>
float(10)
[3]=>
float(5.333333333333333)
}

Fully Dynamic Function:
I took on the task of building a fully dynamic function where you can input as many arrays as you want. I also added a null check as seen in the example below just in case you need to skip a value inside an array.
Function:
# The three dots (...) allow for ANY amount of
# arrays to be inputted into the function
#
# Theoretically you can put 100 different arrays if you wanted
# e.g. arrayAverage($a1, $a2, $a3, $a4, $a5, $a6, ...etc)
function arrayAverage(...$array){
# Add each of the values you want to average out into
# separate temporary arrays for easy manageability.
# For this instance, the first value of the 4 arrays
# will be added to its own array, then the second
# value of the 4 arrays will be added to its own array,
# and so on and so on...
foreach($array as $arr){
for($i = 0; $i < count($arr); $i++){
if(!is_null($arr[$i])) $temparr[$i][] = $arr[$i];
}
}
# Now we can get the average of each of those arrays we created
# and put them into the "$averages" array, to be returned at the end
for($j = 0; $j < count($temparr); $j++){
$averages[] = array_sum($temparr[$j]) / count($temparr[$j]);
}
# Returns the averages in said array
return $averages;
}
Usage/Example:
# Arrays do NOT need the same number of values/keys as shown in "$array2"
$array1 = array(0, 7, 5, 0);
$array2 = array(2, 6, 10, 0, 100);
$array3 = array(4, 8, 15, 10);
$array4 = array(6, 7, 20, 10);
# Example on how to skip values just in case the need arises
# (So our averages won't be affected by having an extra number)
$array5 = array(null, null, null, null, 300);
$averages = arrayAverage($array1, $array2, $array3, $array4, $array5);
var_export($averages);
Output:
[3, 7, 12.5, 5, 200]
Live Sandbox Demo:
https://onlinephp.io/c/bb513

Here is a simple solution but you can generalize it further and make it generic but it will work for now. It can be updated accordingly:
NOTE: Assuming the count of array are same as you have mentioned
$result = [];
for ($i = 0; $i < count($array1); $i++) {
$result [] = ($array1[$i] + $array2[$i] + $array3[$i] + $array4[$i]) / count($array1);
}
dd($result);

Another approach:
$arrays = [$array1, $array2, $array3, $array4];
$result = [];
for ($i = 0; $i < count($array1); $i++) {
$result[] = array_sum(array_column($arrays, $i)) / count($arrays);
}
Working example.

For a sleek, functional-style snippet, use array_map() to "transpose" the rows of data. This means that columns of data will be passed to the custom function. From there, perform the averaging math.
Code: (Demo)
$array1 = [0, 7, 5, 0];
$array2 = [2, 6, 10, 0];
$array3 = [4, 8, 15, 10];
$array4 = [6, 7, 20, 10];
var_export(
array_map(
fn() => array_sum(func_get_args()) / func_num_args(),
$array1,
$array2,
$array3,
$array4
)
);
// fn(...$col) => array_sum($col) / count($col), would also work
Output:
array (
0 => 3,
1 => 7,
2 => 12.5,
3 => 5,
)
Note, this technique will fill gaps in the columns with null (counting as 0) when arrays are not all of the same length: Demo.
If your input array was a single multi-dimensional array, you could use the spread operator to unpack it into array_map().
var_export(array_map(fn() => array_sum(func_get_args()) / func_num_args(), ...$arrays));
To prevent null values from skewing the calculations, filter them before doing the math: Demo.
var_export(
array_map(
fn(...$col) => array_sum($col) / count(array_filter($col, fn($v) => !is_null($v))),
...$arrays
)
);
// or: fn(...$col) => array_sum($col) / count(array_diff($col, ['']))

Related

Merge two arrays into one flat array by extracting 3 elements at a time from each [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
I have two arrays. For example:
$arr1 = [1, 2, 3, 7, 8, 9];
$arr2 = [4, 5, 6, 10, 11, 12, 13, 14];
How can I combine them to general array by taking per 3 elements from every array? The output should be:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
The main idea is taking per 3 elements. Later when I understand the algorithm, the arrays will have objects, not digits. I need to understand how I can to combine two arrays by taking per 3 elements from every array.
This came to mind...
Just keep looping while either array has any elements.
Suck the first three elements from each array and push them into your result array until there is nothing left in the two arrays.
Seems simple enough to me. :)
Code: (Demo)
$arr1 = [1, 2, 3, 7, 8, 9];
$arr2 = [4, 5, 6, 10, 11, 12, 13, 14];
$result = [];
while ($arr1 || $arr2) {
array_push($result, ...array_splice($arr1, 0, 3), ...array_splice($arr2, 0, 3));
}
var_export($result);
Output:
array (
0 => 1,
1 => 2,
2 => 3,
3 => 4,
4 => 5,
5 => 6,
6 => 7,
7 => 8,
8 => 9,
9 => 10,
10 => 11,
11 => 12,
12 => 13,
13 => 14,
)
If you don't want to mutate your original input arrays, this will do: (Demo)
$result = [];
for ($i = 0; isset($arr1[$i]) || isset($arr2[$i]); $i += 3) {
array_push($result, ...array_slice($arr1, $i, 3), ...array_slice($arr2, $i, 3));
}
var_export($result);
So like the comment said you can just merge then sort. The reason for this and why it is a recommended approach is due to the fact that the sort and merge operations apply on the highest level key-value and do not affect sub-objects/arrays inside the merged array.
<?PHP
$array1 = array("color" => "red", 2, 4);
$array2 = array("a", "b", "color" => "green", "shape" => "trapezoid", 4);
$result = array_merge($array1, $array2);
sort($result);
print_r($result);
?>
However, if you really wanted to do an "every 3 elements" method. You can do it by
looping from 0 to n_smallest_length array and then just appending the rest of the larger array to the end and then sorting in 2 places to make sure the next set is being appended into an already sorted array
sorting the array at each iteration
or sorting at the end
<?PHP
$array_one_size = sizeof($array1);
$array_two_size = sizeof($array2);
$smallest_size = $array_one_size < $array_two_size ? $array_one_size : $array_two_size;
$result = array();
for ($i = 0; $i < $smallest_size; $i += 3) {
$result_tmp = array($array1[$i], $array1[$i + 1], $array1[$i + 2], $array2[$i], $array2[$i + 1], $array2[$i + 2]);
$result = array_merge($result, $result_tmp);
sort($result);
}
if ($smallest_size == $array_one_size) {
$result = array_merge($result, array_slice($array1, $i);
} else {
$result = array_merge($result, array_slice($array2, $i);
}
sort($result);
print_r($result);
?>
Note: Also, the case shown above works really well with easily sortable elements. If you want to go for a more complex element array then just replace the sort($result); lines with a custom sorting algorithm that fits your needs.

PHP: different elements between two arrays

I have two different arrays like this
$array1 = [1, 2, 8, 10];
$array2 = [2, 4, 6, 8, 10, 15, 1];
I want to get the common elements and uncommon elements between them.
I almost figured out how to get the common ones as the code below but I can't get uncommon elements.
for($x = 0; $x < count($array1); $x++) {
for($z = 0; $z < count($array2); $z++) {
if ( $array1[$x] == $array2[$z] ) {
$array3 = $array1[$x];
print_r($array3);
} elseif ($array1[$x] !== $array2[$z]) {
// code...
}
}
}
How to get those uncommon or different elements between the two arrays without using a built-in PHP method then output them in a new array.
You can get the uncommon elements by using in_array() function
<?php
$array1 = [1, 2, 8, 10];
$array2 = [2, 4, 6, 8, 10, 15, 1];
$result = [];
for($i = 0;$i < sizeof($array2);$i++){
if(!in_array($array2[$i],$array1)){
$result[] = $array2[$i];
}
}
?>
Output
Array
(
[0] => 4
[1] => 6
[2] => 15
)

How to get max element at each index while comparing two arrays?

I have two indexed arrays of identical length:
$first_array = [1,3,4,5,6];
$second_array = [5,2,1,7,9];
I need to generate a new array that consists of the higher value between the two elements at each index.
The output should be:
$output_array[5, 3, 4, 7, 9];
Super easy one-liner:
Pass both arrays to array_map(), as it synchronously loops through both sets of data, call max() on the two elements.
Code: (Demo)
$first_array = [1, 3, 4, 5, 6];
$second_array = [5, 2, 1, 7, 9];
var_export(array_map('max', $first_array, $second_array));
Output:
array (
0 => 5,
1 => 3,
2 => 4,
3 => 7,
4 => 9,
)
Try this way. demo
<?php
$first_array = array(1,3,4,5,6);
$second_array = array(5,2,1,7,9);
$return = array();
foreach($first_array as $key => $value){
if($first_array[$key] > $second_array[$key]){
$return[] = $first_array[$key];
}else{
$return[] = $second_array[$key];
}
}
print_r($return);

Merge two flat arrays and omit values from one array when the other array has more occurrences of the same value

I want to merge every element of two arrays, BUT if a value is in both arrays, then only add the values from the array which has the biggest amount of that element. The result array does not need to be sorted in any special way, but I did it here for readability.
Sample input:
$array1 = [1, 4, 7, 3, 3, 3];
$array2 = [4, 0, 3, 4, 9, 9];
Desired result:
[0, 1, 3, 3, 3, 4, 4, 7, 9, 9]
//a2 a1 a1 a1 a1 a2 a2 a1 a2 a2
Note, this will be used on big arrays, with unknown integer values. Is there a good way to do this that doesn't require too much time/processing power?
Try this:
<?php
$array1 = [1, 4, 7, 3, 3, 3];
$array2 = [4, 0, 3, 4, 9, 9];
function min_merge($arr1, $arr2) {
$arr1 = array_count_values($arr1);
$arr2 = array_count_values($arr2);
foreach ($arr2 as $index => $arr)
if (!isset($arr1[$index]) || $arr > $arr1[$index])
$arr1[$index] = $arr;
foreach ($arr1 as $index => $arr)
for ($i = 0; $i < $arr; $i++)
$final[] = $index;
return $final;
}
print_r(min_merge($array1, $array2));
Output:
Array (
[0] => 1
[1] => 4
[2] => 4
[3] => 7
[4] => 3
[5] => 3
[6] => 3
[7] => 0
[8] => 9
[9] => 9
)
Unsorted, but it contains all the numbers from [0, 1, 3, 3, 3, 4, 4, 7, 9, 9].
$count[0] = array_count_values($arr1);
$count[1] = array_count_values($arr2);
$out = array();
array_map(function($e) use(&$out, $count){
$n1 = (isset($count[0][$e])) ? $count[0][$e] : 0;
$n2 = (isset($count[1][$e])) ? $count[1][$e] : 0;
$next = ($n2 > $n1) ? array_fill(0, $n2, $e) : array_fill(0, $n1, $e);
$out = array_merge($out, $next);
}, array_keys($count[0] + $count[1]));
print_r($out);
My modernized rewrite of #DaveChen's answer using PSR-12 coding standards and eliminating single-use declarations. This approach uses one loop to determine the greater count for numbers shared by both value-count arrays, then a second loop to populate the result array. (Demo)
$counts1 = array_count_values($array1);
foreach (array_count_values($array2) as $number => $count) {
if ($count > ($counts1[$number] ?? 0)) {
$counts1[$number] = $count;
}
}
$result = [];
foreach ($counts1 as $number => $count) {
array_push($result, ...array_fill(0, $count, $number));
}
var_export($result);
My modernized rewrite of #Expedito's answer which does not abuse the array_map() (when array_map()'s return value is not used, use array_walk() for functional style programming), uses a foreach() loop to eliminate variable scope issues, and generally implements D.R.Y. techniques. (Demo)
$counts1 = array_count_values($array1);
$counts2 = array_count_values($array2);
$result = [];
foreach ($counts1 + $counts2 as $num => $cnt) {
array_push(
$result,
...array_fill(
0,
max($counts1[$num] ?? 0, $counts2[$num] ?? 0),
$num
)
);
}
var_export($result);
And I wanted to add a new approach of my own, despite the fact that it may or may not perform better than the other two snippets. The script makes one pass over the first value count arrays to populate a temporary array which demands which numbers from the first array should be represented in the result array. Then it isolates value intersections from the first array, value differences from the second array, then merges them. (Demo)
$counts1 = array_count_values($array1);
$counts2 = array_count_values($array2);
$keepFrom1 = array_keys(
array_filter(
$counts1,
fn($count, $number) => ($counts2[$number] ?? 0) <= $count,
ARRAY_FILTER_USE_BOTH
)
);
var_export(
array_merge(
array_intersect($array1, $keepFrom1),
array_diff($array2, $keepFrom1)
)
);
probably not the most optimized but
<?php
$one=[1, 4, 7, 3, 3, 3];
$two=[4, 0, 3, 4, 9, 9];
sort($one);
sort($two);
foreach($one as $el)
{
$combined[]=$el;
if (array_search($el,$two))
{
unset($two[array_search($el,$two)]);
}
}
foreach($two as $el)
{
$combined[]=$el;
}
sort($combined);
print_r($combined);
?>

PHP Array Combine and Sum

I have multiple arrays, that get generated when a for loop completes. Now I need to get the total of all these arrays together, but in order, for instance:
array1(2, 4, 6, 8, 10)
array2(2, 4, 6, 8, 10)
I need to add the 2's together, the 4's etc etc
Then put them into another array.
Some combination of array_combine and array_sum seems to be the solution but I can't figure it out.
Any help is greatly appreciated.
You could do this without any php function except count,
$limit = count($array1);
for ($i = 0; $i < $limit; $i++) {
$array_res[$i] = $array1[$i] + $array2[$i];
should work. This will combine your two arrays and add them in the same order. But be sure you used sort or ksort on both of your arrays before if you're not sure they are in the same order.
1st stlye
$a1 = array(
"a" => 2
,"b" => 0
,"c" => 5
);
$a2 = array(
"a" => 3
,"b" => 9
,"c" => 7
,"d" => 10
);
$a3 = array_merge($a1, $a2);
print_r($a3);
2nd style
$a3 = $a1;
foreach($a2 as $k=>$v) {
if(array_key_exists($k,$a3))
$a3[$k] + = $v;
else
$a3[$k] = $v;
}
You should use array_map():
$arr1 = array(2, 4, 6, 8, 10);
$arr2 = array(1, 2, 3, 4, 5);
$arr3 = array_map(
function($foo, $bar){
return $foo+$bar;
},
$arr1, $arr2
);
print_r($arr3); // outputs:
Array
(
[0] => 3
[1] => 6
[2] => 9
[3] => 12
[4] => 15
)
You can do something like this
$a = array(2, 4, 6, 8, 10);
$b = array(2, 4, 6, 8, 10);
$c = array_map("test", $a, $b);
function test($a, $b) {
return $a + $b;
}
print_r($c);
As far as I understand your question You want sum of all the similar digits in both the array:
<?php
$array1= array(2, 4, 6, 8, 10);
$array2=array(2, 4, 6, 8, 10);
$array_sum=array();
foreach($array1 as $key1=>$val1)
{
$sum=0;
foreach($array2 as $key2 => $val2)
{
if($val1==$val2)
{
$sum=$sum+$val1;
}
}
$array_sum[]=$sum;
}
print_r($array_sum);
?>

Categories