Sum of all values on key with different arrays - php

Below are five arrays. The idea is to count all the values for matching keys. And keep the single appearances.
All these should appear in a new array. So, 14855 should have value 6, and 101 value 7 etc.
$arr_one = Array ( [14638] => 5 [14855] => 5 )
$arr_two = Array ( [101] => 4 [10141] => 4 [1015] => 4 [1020] => 4 [10353] => 4 [1048] => 4 [10582] => 4 [1060] => 4 [10675] => 4 [1068] => 4 [1084] => 4 [1098] => 4
$arr_three = Array ( [101] => 3 [10141] => 3 [602] => 3 [341] => 3 [3523] => 3 [922] => 3 [2099] => 3 [7305] => 3 [222] => 3 [537] => 3 [2792] => 3
$arr_four = Array ( [10141] => 2 [1232] => 2 [10909] => 2 [129] => 2 [155] => 2 [] => 2 [156] => 2
$arr_five = Array ( [14855] => 1 [96] => 1 [120] => 1 [129] => 1 [155] => 1 [156] => 1
Is there a way to do this, and with the option that you can add more arrays later as well?
Hope anyone can help me with this brainteaser for me!

This was a challenged question, but at the same time a nasty one ;)
I enjoyed 3 hours works and it is done.
First of all to say your array in the question is not well formed.
This question can be for sure solved in many ways. This is an example of one approach to achieve the goal and demonstrate how to do it, so you are welcome to play with it and learn more.
I wrote some notes inside the code. You can expand this to handle unlimited arrays, but the sum calculation is only for 2 keys, if you have more then 2 keys, I will leave to you, as now you have the concept.
<?php
$arr1 = [14638 => 5, 14855 => 5];
$arr2 = [101 => 4, 10141 => 4, 1015 => 4, 1020 => 4, 10353 => 4, 1048 => 4, 10582 => 4, 1060 => 4, 10675 => 4, 1068 => 4, 1084 => 4, 1098 => 4];
$arr3 = [101 => 3, 10141 => 3, 602 => 3, 341 => 3, 3523 => 3, 922 => 3, 2099 => 3, 7305 => 3, 222 => 3, 537 => 3, 2792 => 3];
$arr4 = [10141 => 2, 1232 => 2, 10909 => 2, 129 => 2, 155 => 2, 0 => 2, 156 => 2];
$arr5 = [14855 => 1, 96 => 1, 120 => 1, 129 => 1, 155 => 1, 156 => 1];
//We merge arrays
$arrMerge = array($arr1, $arr2, $arr3, $arr4, $arr5);
//Count how many keys in merged array subtract 1 for out for loop
$arrCount = count($arrMerge) - 1;
//Our new array that contain a copy of all keys and values with out doubles
$arrNew = array();
//Creating new array of all arrays
for ($i = 0; $i < $arrCount; $i ++)
{
foreach ($arrMerge[$i] as $key => $value)
{
//echo "Key: $key; Value: $value<br />\n";
$arrNew[$key] = $value;
}
}
//The algorithm
for ($i = 0; $i < $arrCount; $i ++)
{
echo "<b>Array " . $i . " comparing with : </b>";
for ($j = $arrCount; $j > $i; $j --)
{
echo "<br> Array " . $j . " : <br/>";
for ($k = 0; $k < count($arrMerge[$i]); $k ++)
{
$key1 = array_keys($arrMerge[$i]);
$value1 = array_values($arrMerge[$i]);
for ($l = 0; $l < count($arrMerge[$j]); $l ++)
{
$key2 = array_keys($arrMerge[$j]);
$value2 = array_values($arrMerge[$j]);
if ($key1[$k] == $key2[$l])
{
echo "match found: " . $key1[$k] . " and " . $key2[$l] . " are identical keys, ";
echo "we sum : " . $value1[$k] . " and " . $value2[$l] . "<br />";
//We update the new array with the summed values.
$arrNew[$key1[$k]] = $value2[$l] + $value1[$k];
}
}
}
}
echo "<br><br>";
}
// printing results
echo "<b>This our new array with sum values</b><br/>";
foreach ($arrNew as $key => $value)
{
echo "Key: $key; Value: $value<br />\n";
}
?>
It is tested and here is the output of this code, The first part is a list of matching keys and last part as you can see the key 14855 got value 6 and key 101 got value 7 etc.:
Comparing all 5 Arrays Keys output
Array 0 comparing with :
Array 4 :
match found: 14855 and 14855 are identical keys, we sum : 5 and 1
Array 3 :
Array 2 :
Array 1 :
Array 1 comparing with :
Array 4 :
Array 3 :
match found: 10141 and 10141 are identical keys, we sum : 4 and 2
Array 2 :
match found: 101 and 101 are identical keys, we sum : 4 and 3
match found: 10141 and 10141 are identical keys, we sum : 4 and 3
Array 2 comparing with :
Array 4 :
Array 3 :
match found: 10141 and 10141 are identical keys, we sum : 3 and 2
Array 3 comparing with :
Array 4 :
match found: 129 and 129 are identical keys, we sum : 2 and 1
match found: 155 and 155 are identical keys, we sum : 2 and 1
match found: 156 and 156 are identical keys, we sum : 2 and 1
Last part our new Array with sum of each Key
This our new array with sum values
Key: 14638; Value: 5
Key: 14855; Value: 6
Key: 101; Value: 7
Key: 10141; Value: 5
Key: 1015; Value: 4
Key: 1020; Value: 4
Key: 10353; Value: 4
Key: 1048; Value: 4
Key: 10582; Value: 4
Key: 1060; Value: 4
Key: 10675; Value: 4
Key: 1068; Value: 4
Key: 1084; Value: 4
Key: 1098; Value: 4
Key: 602; Value: 3
Key: 341; Value: 3
Key: 3523; Value: 3
Key: 922; Value: 3
Key: 2099; Value: 3
Key: 7305; Value: 3
Key: 222; Value: 3
Key: 537; Value: 3
Key: 2792; Value: 3
Key: 1232; Value: 2
Key: 10909; Value: 2
Key: 129; Value: 3
Key: 155; Value: 3
Key: 0; Value: 2
Key: 156; Value: 3

Related

Sort an array of numbers into two arrays of equal length in PHP

I have an array of 20 different numbers which contains ranking of students.
I want to split this array into two sub arrays of equal length i.e 10
I also want the sum of all numbers within each array to be close.
For example, in sub-array A there could be a total sum of 56 and in sub-array B there could be a total sum of 57.
I am using PHP.
I sort the main array here and would like to assign index[0] to sub-array A and index[1] to sub-array B, and keep repeating this until both arrays are filled.
My approach works but i think its not great and not dynamic.
I interate through the main original array for [i] and then add that to the first sub-array, then I set i = i+2 so that I get every second value and store them in the first array.
I then remove the value at index[i] from the main array.
What is left over is now sub-array B.
$kids = array (8,5,6,9,3,8,2,4,6,10,8,5,6,1,7,10,5,3,7,6);
sort($kids);
$arrlength = count($kids);
for($x = 0; $x < $arrlength; $x++) {
echo $kids[$x];
echo "<br>";
}
$teamA = array();
$teamB = array();
$i = 0;
while ($i < $arrlength)
{
#echo $kids[$i] ."<br />";
array_push($teamA, $kids[$i]);
unset($kids[$i]);
$i += 2;
}
$teamB = $kids;
print_r($teamA);
print_r($teamB);
My Output is :
Array ( [0] => 1 [1] => 3 [2] => 4 [3] => 5 [4] => 6 [5] => 6 [6] => 7 [7] =>
8 [8] => 8 [9] => 10 )
The sum here of all values is = 58
Array ( [1] => 2 [3] => 3 [5] => 5 [7] => 5 [9] => 6
[11] => 6 [13] => 7 [15] => 8 [17] => 9 [19] => 10 )
The sum here of all values is = 61
Any help is greatly appreciated. I have no real experience with PHP or its built in functions so sorry if this is a basic question. Thanks!
There is a built-in helper function of php, array_slice. You can read about it in the link I provided.
Here's how you can use in to achieve what you want:
$kids = array (5,7,6,8,3,8,2,4,6,10,8,5,6,10,7,6,5,3,7,6);
sort($kids);
$arrlength = count($kids);
$arrayA= array_slice($kids, 0, $arrlength / 2);
$arrayB= array_slice($kids, $arrlength / 2);
Output
// $arrayA
array:10 [▼
0 => 2
1 => 3
2 => 3
3 => 4
4 => 5
5 => 5
6 => 5
7 => 6
8 => 6
9 => 6
]
// $arrayB
array:10 [▼
0 => 6
1 => 6
2 => 7
3 => 7
4 => 7
5 => 8
6 => 8
7 => 8
8 => 10
9 => 10
]
Another approach for achieving what you asked
$kids = array(8,5,6,9,3,8,2,4,6,10,8,5,6,1,7,10,5,3,7,6);
sort($kids);
$teamA = array();
$teamB = array();
foreach($kids as $i => $kid){
if($i % 2){
array_push($teamA, $kid);
} else{
array_push($teamB, $kid);
}
}
It will generate the same output and sum as you want.

how to compare 2 array and compare difference of same id in php?

this questin is asked many times but every one using same array but in my case i have 2 arrays
consider i have 2 arrays
array1:3 [
10 => 900.0
20 => 450.0
30 => 600.0
]
array2:3 [
30 => 200.0
10 => 500.0
20 => 600.0
]
output should be
[900.0 - 500 = 400 // according to same id 10 = 10
450.0 - 600 = -150 // 20 = 20
600.0 - 200 = 400 // 30 = 30
]
in this array consider 10,20,30 are ids and next is value i want output where compare ever id and get difference example if (id1 = id2 ){ id1 => value - id2 => value }
i need help in that code which i already tried
$getsellerreport = SellerSellsReport::where('seller_id' , $seller_id);
$getunitdiff = $getsellerreport->pluck('unit')->toArray();// [0 => 75 1 => 500 => 100]
$getamountdiff = $getsellerreport->pluck('amount')->toArray(); // [0 => 11000 => 40 2 => 900]
$getproductdiff = $getsellerreport->pluck('product_id')->toArray(); // [0 => 39 1 => 242 => 23]
foreach($product_report as $preport){
$unit[] = $preport['unit'];// [0 => 75 1 => 25 2 => 100]
$amount[] = $preport['amount'];// [0 => 900 1 => 450 2 => 600]
$product_id[] = $preport['product_id'];// [0 => 23 1 => 242 => 39]
} // here we get array two values
above code get values with starting 0 key value and on below for() loop we can use product_id to compare both product id and get unit and amount but i dont know how i can do that can someone help me?
for ($i = 0 ; $i < sizeof($amount) ; $i++){
$unitdiff[] = $getunitdiff[$i] - $unit[$i];
$amountdiff[] = $getamountdiff[$i] - $amount[$i];
}
You could collect the arrays and use map, here is a sample to get you started:
$a = [
10 => 900.0,
20 => 450.0,
30 => 600.0,
];
$b = [
30 => 200.0,
10 => 500.0,
20 => 600.0,
];
$x = collect($a)->map(function($aItem, $index) use ($b) {
return $aItem - $b[$index];
});
dd($x); // yields [ 10 => 400.0, 20 => -150.0, 30 => 400.0 ]

PHP - How to count all the values of an array with limited ranges?

I have an array like this:
$array = array(10,25,47,14,45,58,25,29,15,36,45,15,25,27,34);
is there a way to output a new array of 10 ranges with key that tells me which is used and frequency as values?
$result = array(
[x0] => frequency // number of values <= x0
[x1] => frequency // number of values > x0 and <=1
etc..., [x2], ...., [x7], x[8]
[x9] => frequency // number of values >= x9
)
use this for 10 equal segments
$array = array(10,25,47,14,45,58,25,29,15,36,45,15,25,27,34);
$step = (max($array) - min($array)) / 10;
$result = [];
for ($i = min($array); $i < max($array) - $step; $i += $step) {
$res = array_filter($array, function($v) use ($i, $step) {
return ($i <= $v) && $v < $i +$step;
});
$result[$i . '-' . ($i + $step)] = $res;
}
Return:
"10 - 14.8" => 2
"14.8 - 19.6" => 2
"19.6 - 24.4" => 0
"24.4 - 29.2" => 5
"29.2 - 34" => 0
"34 - 38.8" => 2
"38.8 - 43.6" => 0
"43.6 - 48.4" => 3
"48.4 - 53.2" => 0
"53.2 - 58" => 0
You can use array_count_values() to count values
$array = array(10,25,47,14,45,58,25,29,15,36,45,15,25,27,34);
$vals = array_count_values($array);
echo "<pre>"; print_r($vals);
This will give you
Array
(
[10] => 1
[25] => 3
[47] => 1
[14] => 1
[45] => 2
[58] => 1
[29] => 1
[15] => 2
[36] => 1
[27] => 1
[34] => 1
)
I've used an array for the range boundaries. Here with an example of 4 irregular ranges. And dumped the sorted array to make it easier to see if the results are as you'd expect.
<?php
$array = array(10,25,47,14,45,58,25,29,15,36,45,15,25,27,34);
$bounds = array(0,10,25,50,100);
$lower = array_shift($bounds);
$range_frequencies = array();
sort($array);
var_dump($array);
foreach($bounds as $upper) {
$range_frequencies[$lower . '-' . $upper] = 0;
foreach($array as $k => $v) {
if($v > $lower && $v <= $upper) {
$range_frequencies[$lower . '-' . $upper]++;
unset($array[$k]);
}
}
$lower = $upper;
}
var_dump($range_frequencies);
Output:
array (size=15)
0 => int 10
1 => int 14
2 => int 15
3 => int 15
4 => int 25
5 => int 25
6 => int 25
7 => int 27
8 => int 29
9 => int 34
10 => int 36
11 => int 45
12 => int 45
13 => int 47
14 => int 58
array (size=4)
'0-10' => int 1
'10-25' => int 6
'25-50' => int 7
'50-100' => int 1
Based on Manjeet Barnala's answer:
$array = array(10,25,47,14,45,58,25,29,15,36,45,15,25,27,34);
$vals = array_count_values($array);
arsort($vals);
$vals = array_slice($vals,0,10,true);
var_dump($vals);

How to use array_push with associative array and index key?

I am a bit 'rusty with php as it happens that sometimes I use it for weeks and sometimes it happens that you do not use for months. Either way I'm trying to pass values of another array are "array", on another array in an orderly manner ... What I want to do is essentially create a key that allows me to organize incremental values per line, in particular;
array content
Array
(
[key] => value
[2] => 1
[3] => Inter
[4] => 4
[5] => 4
[6] => 0
[7] => 0
[8] => 5
[9] => 1
[10] => +4
[11] => 12
[12] => Chievo Verona - Inter 0 - 1
[13] => Inter - Milan 1 - 0
[14] => Carpi - Inter 1 - 2
[15] => Inter - Atalanta 1 - 0
[16] => ;
[17] => 2
[18] => Torino
[19] => 4
[20] => 3
[21] => 1
[22] => 0
[23] => 9
[24] => 4
[25] => +5
[26] => 10
[27] => Torino - Sampdoria 2 - 0
[28] => Hellas Verona - Torino 2 - 2
[29] => Torino - Fiorentina 3 - 1
[30] => Frosinone - Torino 1 - 2
[31] => ;
[32] => 3
[33] => Fiorentina
[34] => 4
[35] => 3
[36] => 0
[37] => 1
[38] => 5
[39] => 3
[40] => +2
[41] => 9
[42] => Carpi - Fiorentina 0 - 1
[43] => Fiorentina - Genoa 1 - 0
[44] => Torino - Fiorentina 3 - 1
[45] => Fiorentina - Milan 2 - 0
[46] => ;
[47] => 4
[48] => Roma
[49] => 4
[50] => 2
the ";" It'll need to be able to recognize where you break the line, I do not remember if there is any method that allows me to access the next key.
Currently my code is:
$classifica = array("key" => "value");
function buildArrayClassifica()
{
global $array;
global $classifica;
$i = 0;
foreach(array_slice($array,1) as $key => $value)
{
if($value != ";")
{
array_push($classifica[$i], $value); //there is a problem
echo $value . " ";
}
else if($value == "value ")
{
continue;
}
else
{
$i++;
echo "<br/>";
}
}
}
The code I will return this error:
Warning: array_push () Expects parameter 1 to be array, null given in...
in particular on array_push, it seems not to accept incremental keys or maybe I'm doing it the wrong way.
Can anyone tell me how to solve?
UPDATING
As you have seen the issue is not simple and it is quite difficult to explain the problem, but I will try to be even clearer to meet.
As you can see above you are the structure of the array "array", but is a disordered structure that needs to be ordered in an additional array. To recapitulate the structure of the array "array" is:
1 , Inter , 4 , 4 , 0 , 0 , 5 , 1 , +4 , 12 , Chievo Verona - Inter 0 - 1 , Inter - Milan 1 - 0 , Carpi - Inter 1 - 2 , Inter - Atalanta 1 - 0 , ;
the ";" means that the line is finished. So the next value near the ";" means that a new line coming. What I need is move all the value of "array" in array classifica, but I want organize them for:
ROW1 => 1 , Inter , 4 , 4 , 0 , 0 , 5 , 1 , +4 , 12 , Chievo Verona - Inter 0 - 1 , Inter - Milan 1 - 0 , Carpi - Inter 1 - 2 , Inter - Atalanta 1 - 0
ROW2 => Other values...
So the ROW1, 2 .. rapresents the key of the array classifica. I'm trying to push the value inside a row and after it increment $i index but the code doesn't add the value because the index replace in loop the actual key, for example:
actual foreach content:
$i = 0
value = "Inter"
content of array=> [0] => Inter
now the $i is ever 0 because the row isn't finished yet, the ";"
it has not yet been reached, so the next content of foreach is:
"1" but replace the "Inter" value, so this is a problem.
You cannot use array_push() in this way. Please try:
$classifica = array();
function buildArrayClassifica()
{
global $array;
global $classifica;
$i = 0;
foreach(array_slice($array,1) as $key => $value)
{
if($value != ";")
{
$classifica[$i] = $value;
echo $value . " ";
}
else if($value == "value ")
{
continue;
}
else
{
$i++;
echo "<br/>";
}
}
}
This will create indexes (the value of $i) when $value is added to your array. array_push() would place the $value at the next numerical index and may not be what you want by the looks of it. You could also use $key if you wanted the index to match.
EDIT
After more discussion, you have a specific format, where the first Item is the Key, the following indexes are values, and when you encounter the value ";", it starts the sequence over. So when we read:
[2] => 1
[3] => Inter
[4] => 4
[5] => 4
[6] => 0
[7] => 0
[8] => 5
[9] => 1
[10] => +4
[11] => 12
[12] => Chievo Verona - Inter 0 - 1
[13] => Inter - Milan 1 - 0
[14] => Carpi - Inter 1 - 2
[15] => Inter - Atalanta 1 - 0
[16] => ;
The first value, '1' is our Index, the following values become the Value for this Index, and we stop reading when we find ";". That would look something like:
<?php
function buildArrayClassifica($dataArray){
$resultArray = array();
$t = array_values($dataArray);
print_r($t);
$lsc = 0;
foreach($t as $k => $v){
if((string)$v == ';'){
echo "<p>Found ';' at [$k] => {$v}</p>";
// Found end of data
// Save position
$scp = $k;
echo "<p>Recorded [$scp] position for ';'.</p>";
// Reset to find the Index, first int in this series
$c=$lsc; // First pass this should be 0
// Set the index
if($lsc ==0){
// First pass
$index = intval($t[$c]);
echo "<p>Getting Index from position [" . ($c) ."] => $index for Result Array.</p>";
$c++;
} else {
$c++;
$index = intval($t[$c]);
echo "<p>Getting Index from position [" . ($c) ."] => $index for Result Array.</p>";
$c++;
}
echo "<p>Starting to read data from [$c] until [$scp].</p>";
// Init implode variable
$data = "";
for($c;$c<$scp;$c++){
//Populate variable with the series up to semicolon, skipping first element (index)
$data .= $t[$c] . ", ";
}
echo "<p>Data collected for this round: '" . htmlentities(substr($data,0,-2)) . "'</p>";
// populate result array
$resultArray[$index] = substr($data,0,-2);
echo "<p>resultArray[$index] => " . htmlentities($resultArray[$index]) . "</p><br />";
$lsc = $scp;
}
}
return $resultArray;
}
$oldArray = array(1, "Inter", 4 , 4 , 0 , 0 , 5 , 1 , "+4" , 12 , "Chievo Verona - Inter 0 - 1", "Inter - Milan 1 - 0", "Carpi - Inter 1 - 2", "Inter - Atalanta 1 - 0", ";", 2, "Torino", 4, 3, 1, 0, 9, 4, '+5', 10, "Torino - Sampdoria 2 - 0", "Hellas Verona - Torino 2 - 2", "Torino - Fiorentina 3 - 1", "Frosinone - Torino 1 - 2", ";", 3, "apple", 0, 4, 6, "apple", ";");
$classifica = buildArrayClassifica($oldArray);
print_r($classifica);
?>
My initial testing seems to work for what you described. The first element of the array becomes the Index, the next few values become imploded until we reach the semicolon (;) value.
What I see as a result:
Array ( [1] => Inter, 4, 4, 0, 0, 5, 1, +4, 12, Chievo Verona - Inter 0 - 1, Inter - Milan 1 - 0, Carpi - Inter 1 - 2, Inter - Atalanta 1 - 0 [2] => Torino, 4, 3, 1, 0, 9, 4, +5, 10, Torino - Sampdoria 2 - 0, Hellas Verona - Torino 2 - 2, Torino - Fiorentina 3 - 1, Frosinone - Torino 1 - 2 [3] => apple, 0, 4, 6, apple )
ASIDE
If it were me, I would push it all into an array like so:
$data = array();
for($c;$c<$scp;$c++){
$data[] = $t[$c];
}
$resultArray[$index] = $data;
Or if you really want a string:
$resultArray[$index] = implode(", ", $data);
Hope that helps.

Displaying avg reading in seven days interval

Given an array and I need to to display the average after every seventh row
Array
(
[0] => Array
(
[date] => 01-03-2015
[site_id] => 1
[starting_reading] => 567
[close_reading] => 567
)
[1] => Array
(
[date] => 03-03-2015
[site_id] => 1
[starting_reading] => 567
[close_reading] => 567
)
[2] => Array
(
[date] => 08-03-2015
[site_id] => 1
[starting_reading] => 567
[close_reading] => 567
)
)
Now what i need, is to display all avg reading in 7 days like:
1 to 7
--------------------- avg=close-start----------
8 to 14
--------------------- avg=close-start----------
15 to 21
--------------------- avg=close-start----------
22 to 28
--------------------- avg=close-start----------
29 to 31
--------------------- avg=close-start----------
date starting_reading close_reading
01-03-2015
03-03-2015
--------------------- avg=close-start----------
08-03-2015
--------------------- avg=close-start----------
//$arr is as the array you described
foreach($arr as $k => $v){
//$k will be some integer 0...count($arr)-1 assuming a 'normal' index
//$v is your child array, where you can access attributes such as $v['date']
//every seventh row can be done in a number of ways, the easiest way is:
if($k % 7 == 0){
//then show new line. This will happen every time the number divides into seven. 0, 7, 14, 21... etc.
var_dump($v); will output your child of the seventh (multiple) item
}
}
Including your example for dates and averages assuming array is correctly formatted
//$arr is as the array you described
$close = 0;
$start = 0;
foreach($arr as $k => $v){
//$k will be some integer 0...count($arr)-1 assuming a 'normal' index
//$v is your child array, where you can access attributes such as $v['date']
//every seventh row can be done in a number of ways, the easiest way is:
if($k % 7 == 0){
$close = 0; //reset close
$start = 0; //reset start
}
$close += (int)$v['close_reading'];
$start += (int)$v['starting_reading'];
if(($k + 1) % 7 == 0){ //this is the last row, 6, 13, 20 etc.
echo ($k-5).' to '.($k+1);
echo 'Average: '.(($close - $start) / 7);
}
}

Categories