Как объединить несколько массивов и интерполировать суммы значений, если ключи не совпадают? - PullRequest
1 голос
/ 27 марта 2019

Я ищу функцию для объединения 2 или более массивов в выходной массив для использования на графике. Оси X (ключ массива) - это даты, а Y - доллары (значение массива). Иногда даты / ключи могут совпадать или нет. Также длины или массив могут не совпадать. Я нашел примеры того, как это сделать, когда ключи совпадают: Как суммировать все значения столбцов в многомерном массиве? Но я хотел бы интерполировать значения, когда они не совпадают. Я соединил этот график в качестве примера ввода и вывода, который я пытаюсь получить.

example graph

2 красных массива ввода будут:

$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
);

И синий выходной массив будет:

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
)

У меня работает интерполирующая функция:

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;
}

Возвращается 1333,33 в качестве интерполированного значения на дату 2019-1-22.

У меня просто возникают проблемы, когда я зацикливаюсь на цикле по нескольким массивам и когда нужно интерполировать значение вместо простого добавления значений. Любая помощь будет оценена.

1 Ответ

1 голос
/ 27 марта 2019

Вы можете создать вспомогательную функцию, которая принимает один массив ключ / значение и массив ключей, который возвращает массив ключ / значение, который будет содержать все ключи во втором массиве, и интерполирует значения, где это необходимо.Массив ключей должен иметь все ключи, которые существуют в первом массиве, но могут иметь больше (не меньше):

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;
}

Теперь с помощью этой функции легко получить желаемый результат.Допустим, у вас есть $a1 и $a2, как в вашем примере.Затем выполните:

$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 будет иметь желаемый результат.

Более 2 входных массивов

Если у вас есть массив таких входных массивов, давайте вызовемэто $a, тогда вы можете использовать этот код:

$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));
}
...