I have 2 arrays in PHP7:
$Array1 = ["bus","bus","int"];
$Array2 = [2,18,10];
Where $Array1 is key and $Array2 is value for each index.
I need to combine both and sum values for duplicate keys, e.g. get following output:
$Array3 = ["bus" => 20, "int" => 10];
Thank you!
The code you need is as easy as that:
// The input arrays
$Array1 = ['bus', 'bus', 'int'];
$Array2 = [2, 18, 10];
// Build the result here
$Array3 = [];
// There is no validation, the code assumes that $Array2 contains
// the same number of items as $Array1 or more
foreach ($Array1 as $index => $key) {
// If the key $key was not encountered yet then add it to the result
if (! array_key_exists($key, $Array3)) {
$Array3[$key] = 0;
}
// Add the value associate with $key to the sum in the results array
$Array3[$key] += $Array2[$index];
}
print_r($Array3);
Its output:
Array
(
[bus] => 20
[int] => 10
)
This one could work:
$Array1 = ['bus', 'bus', 'int'];
$Array2 = [2, 18, 10];
# Let $Array3 be the required results array.
$Array3 = [];
for($j = 0; $j < count($Array1); $j += 1){
$k = $Array1[$j];
/*If the key already exists in $Array3 , add to it the value in the present key,
else just enter it as a new element. */
if(array_key_exists($k,$Array3)){ $Array3[$k] = $Array3[$k] + $Array2[$j];}
else {
# But first check that the length of $Array2 is not exceeded
if($j <= count($Array2)){
$Array3[$k] = $Array2[$j];
}
}
}
print_r($Array3);
# gives: Array ( [bus] => 20 [int] => 10 )
i will make it. i hope it will helpful for you: you can get your required out put by using an extra array, first of all, count your array elements, this will you condition. this simple check
$Array1[$x] == $Array1[$x+1]
will check if the array consecutive address have same value. (the condition is array must be sorted),
and the other value like this:
$arr[$Array1[$x]] // assign a key
this is for making it associate array :
$Array1 = ["bus","bus","int"];
$Array2 = [2,18,10];
$arr = [];
for ($x = 0; $x < count($Array1); $x++) {
if($Array1[$x] == $Array1[$x+1])
{
$arr[$Array1[$x]] = $Array2[$x] + $Array2[$x+1];
$x++;
}
else
{
$arr[$Array1[$x]] = $Array2[$x];
}
}
the output is:
Array ( [bus] => 20 [int] => 10 )
I want to get generate histogram data for the following array. array_count_values() would be great to use, except it just counts values for an exact value match. How can I elegantly do the same, but bundle values by a given step or interval?
$dataArray = array(385,515,975,1136,2394,2436,4051,4399,4484,4768,4768,4849,4856,4954,5020,5020,5020,5020,5020,5020,5020,5020,5020,5052,5163,5200,5271,5421,5421,5442,5746,5765,5903,5992,5992,6046,6122,6205,6208,6239,6310,6360,6416,6512,6536,6543,6581,6609,6696,6699,6752,6796,6806,6855,6859,6886,6906,6911,6923,6953,7016,7072,7086,7089,7110,7232,7278,7293,7304,7309,7348,7367,7378,7380,7419,7453,7454,7492,7506,7549,7563,7721,7723,7731,7745,7750,7751,7783,7791,7813,7813,7814,7818,7833,7863,7875,7886,7887,7902,7907,7935,7942,7942,7948,7973,7995,8002,8013,8013,8015,8024,8025,8030,8038,8041,8050,8056,8060,8064,8071,8081,8082,8085,8093,8124,8139,8142,8167,8179,8204,8214,8223,8225,8247,8248,8253,8258,8264,8265,8265,8269,8277,8278,8289,8300,8312,8314,8323,8328,8334,8363,8369,8390,8397,8399,8399,8401,8436,8442,8456,8457,8471,8474,8483,8503,8511,8516,8533,8560,8571,8575,8583,8592,8593,8626,8635,8635,8644,8659,8685,8695,8695,8702,8714,8715,8717,8729,8732,8740,8743,8750,8756,8772,8772,8778,8797,8828,8840,8840,8843,8856,8865,8874,8876,8878,8885,8887,8893,8896,8905,8910,8955,8970,8971,8991,8995,9014,9016,9042,9043,9063,9069,9104,9106,9107,9116,9131,9157,9227,9359,9471);
// if array_count_values accepted a step value I could do this:
print_r(array_count_values($dataArray,1000));
// expected result:
// array(1000 => 3, 2000 => 1, ... 10000 => 15);
// ^0-1000 ^[385,515,975]
What do you recommend?
In the event I have to loop through all values manually, is there an elegant way to round all values to a given interval?
$step = 1000;
$result = array_count_values(
array_map(
function ($value) use ($step) {
return (int) ceil($value / $step) * $step;
},
$dataArray
)
);
var_dump($result);
The rounding solution seems pretty straight forward:
$step_size = 10;
$data = array(10, 20, 24, 30, 35, 50);
foreach ($data as $index => $value) {
$data[$index] = round($value / $step_size) * $step_size;
}
// array(10, 20, 20, 30, 40, 50);
You can build the output directly to avoid mapping the entire data array just to make use of array_count_values(); below is a more generic implementation that allows the mapping to be done outside of the function itself:
function array_count_values_callback(array $data, callable $fn)
{
$freq = [];
foreach ($data as $item) {
$key = $fn($item);
$freq[$key] = isset($freq[$key]) ? $freq[$key] + 1 : 1;
}
return $freq;
}
print_r(array_count_values_callback($dataArray, function($item) {
return ceil($item / 1000) * 1000;
}));
Here is a simple solution where you loop through your $dataArray,
$step_size = 1000;
$histogramArray = array();
foreach ($dataArray as $v) {
$k = (int)ceil($v / $step_size) * $step_size;
if (!array_key_exists($k, $histogramArray)) $histogramArray[$k] = 0;
$histogramArray[$k]++;
}
And the output would be,
Array
(
[1000] => 3
[2000] => 1
[3000] => 2
[5000] => 8
[6000] => 21
[7000] => 25
[8000] => 46
[9000] => 110
[10000] => 15
)
How do I combine these two arrays, so that the keys stay the same, but the values are arithmetically determined?
Note - the keys might not always line up in each array, per my example:
$Array1 = [4 => 100, 5 => 200, 6 => 100, 7 => 400];
$Array2 = [2 => 300, 5 => -100, 16 => -500];
Desired output:
$Array3 = [2 => 300, 4 => 100, 5 => 100, 6 => 100, 7 => 400, 16 => -500];
You can use array_map for this:
$Array3 = array_map(function($a,$b) {return $a+$b;},$Array1,$Array2);
However this will only work if you have the same keys in both arrays (which, in your example, you don't).
If this is an issue, the easiest workaround would probably be:
$allKeys = array_merge(array_keys($Array1),array_keys($Array2));
$Array3 = Array();
foreach($allKeys as $k) {
$Array3[$k] = (isset($Array1[$k]) ? $Array1[$k] : 0)
+(isset($Array2[$k]) ? $Array2[$k] : 0);
}
EDIT Just realised the above code is not optimal. Rewriting:
$allKeys = array_unique(array_merge(array_keys($Array1),array_keys($Array2)));
// rest of code as above
Actually not sure if the overhead of repeated keys is more or less than the overhead of checking uniqueness...
You can foreach over each array and add them to a result array.
//$array3 = array();
//foreach($array1 as $k=>$v){
// $array3[$k] = $v;
//}
$array3 = $array1;
foreach($array2 as $k=>$v){
$array3[$k] = isset($array3[$k]) ? $array3[$k]+$v : $v;
}
I have an array like this:
$array = [
0 => 'Apple',
2 => 'Orange',
5 => 'Pear',
8 => 'Pear'
]
Is there a way to fill in the missing indexes with a default value (for example, an empty string or null)?
I'd like to insert new elements into the array at the following keys: 1, 3, 4, 6, 7
My result should be:
[
0 => 'Apple',
1 => '',
2 => 'Orange',
3 => '',
4 => '',
5 => 'Pear',
6 => '',
7 => '',
8 => 'Pear'
]
This should be faster for larger arrays. For smaller arrays any method will do.
$existingKeys = array_keys($array);
//you can use any value instead of null
$newKeys = array_fill_keys(range(min($existingKeys), max($existingKeys)), null);
$array += $newKeys;
//optional, probably not needed
ksort($array);
for($i=0;i<count($array);++$i){
$array[$i] = isset($array[$i])? $array[$i] : '';
}
It just fills the missing keys with an empty string, though. Not sure if this suits you.
Edit
Just noticed Perr0_hunter wrote pretty much the same thing before I did :P
you could try a for() from the lowest index to the highest and complete if it's empty
for($i = 0 ;$i <= 8 ; $i++)
{
//if it's not set
if(!isset($array[$i]))
{
//set to empty
$array[$i] = "";
}
}
Additionally you could count first the number of elements on the array and wrap it in a function
function completeIndexes($array)
{
$total = count($array);
for($i = 0 ;$i < $total ; $i++)
{
//if it's not set
if(!isset($array[$i]))
{
//set to empty
$array[$i] = "";
}
}
return $array;
}
Sensibly, you can use a manual loop from 0 to the last numeric key and populate a new array. (Of course, if the array keys are not already sorted in an ascending fashion, you will need to isolate the max() array_key() to find the final key of the newly formed array.)
Or you can use a functional approach to overwrite a default-value-filled, temporary array with the input array's data.
Here are two valid approaches: (Demo)
$result = [];
for (
$i = 0, $last = array_key_last($array);
$i <= $last;
++$i
) {
$result[$i] = $array[$i] ?? null;
}
var_export($result);
And
var_export(
array_replace(
array_fill(0, array_key_last($array), null),
$array
)
);
p.s. Note that array_merge() and the "array union operator" (+) are not suitable techniques to join the default array with the original array -- or at best, the union operator needs to be followed by a ksort() call.
Demo of technique that I do NOT endorse: https://3v4l.org/lCS0n
If what you're trying to do is reorder the array so you get
Array( [0] => Apple [1] => Orange [2] => Pear [3] => Pear )
Just create a new Array and copy the values into it. It will allocate new indexes sequentially
i.e.
$new_array = array();
for( $value in $old_array )
$new_array[] = $value;