Reputation: 295
I'm looking for a function to merge 2 or more arrays into an output array to use on a graph. The X axes (array key) are dates & the Y are Dollars (array value). Sometimes the dates/keys may match up or they may not. Also the lengths or the array may not be the same. I've found examples on how to do this when the keys match: How to sum all column values in multi-dimensional array? But I'd like to interpolate the values when they don't match. I've put this graph together as an example of the input & output I'm try to get.
The 2 red input arrays would be:
$a1 = array(
"2019-01-01" => 0
,"2019-01-15" => 1000
,"2019-02-05" => 2000
,"2019-02-19" => 4000
);
$a2 = array(
"2019-01-22" => 0
,"2019-02-05" => 1000
,"2019-02-12" => 2000
,"2019-02-26" => 3000
);
And the blue output array would be:
Array
(
[2019-01-01] => 0
[2019-01-15] => 1000
[2019-01-22] => 1333
[2019-02-05] => 3000
[2019-02-12] => 5000
[2019-02-19] => 6500
[2019-02-26] => 7000
)
I've got the interpolate function working:
echo getFeeFromDates('2019-1-15', 1000, '2019-2-5', 2000, '2019-1-22');
function getFeeFromDates ($date1, $fee1, $date2, $fee2, $getDate) {
$start = strtotime($date1);
$end = strtotime($date2);
$find = strtotime($getDate);
$days_between = ceil(abs($end - $start) / 86400);
$fee = abs($fee2 - $fee1);
$feePerDay = $fee / $days_between;
$findDays = ceil(abs($find - $start) / 86400);
$myFee = number_format(($feePerDay * $findDays) + $fee1, 2);
return $myFee;
}
This will return 1333.33 as the interpolated value on the 2019-1-22 date.
I'm just having trouble wrapping my head around looping through the multiple arrays & when to interpolate the value vs. just adding the values. Any help would be appreciated.
Upvotes: 1
Views: 205
Reputation: 350310
You could create a helper function that takes one key/value array and an array of keys, which returns a key/value array that will contain all the keys in the second array, and interpolated values where needed. The array of keys should have all the keys that exist in the first array, but can have more (not less):
function interpolate($a, $keys) {
foreach($keys as $key) {
if (key($a) === $key) {
$prevValue = $result[$key] = current($a);
$prevKey = $key;
next($a);
} else if (empty($prevKey)) {
$result[$key] = 0;
} else {
$result[$key] = current($a) === false ? $prevValue
: $prevValue + (current($a) - $prevValue)
* (strtotime($key) - strtotime($prevKey))
/ (strtotime(key($a)) - strtotime($prevKey));
}
}
return $result;
}
Now with this function it is easy to get the desired result. Let's say you have $a1
and $a2
as in your example. Then do:
$keys = array_keys(array_merge($a1, $a2));
sort($keys);
$b1 = interpolate($a1, $keys);
$b2 = interpolate($a2, $keys);
foreach($b1 as $key => $value) {
$sum[$key] = $value + $b2[$key];
}
$sum
will have the desired result.
When you have an array of such input arrays, let's call it $a
, then you can use this code:
$keys = array_keys(array_merge(...$a));
sort($keys);
$b = array_map(function ($a1) use ($keys) {
return interpolate($a1, $keys);
}, $a);
foreach($keys as $key) {
$sum[$key] = array_sum(array_column($b, $key));
}
Upvotes: 1