根据已选择的日期/时间从阵列中获取最接近的日期/时间

时间:2016-11-07 10:01:15

标签: php arrays

使用一个已选择的日期: Test example

$dates[] = array("date" => "2016-02-18 02:00:00", "duration" => "600"); // 10 mins
$dates[] = array("date" => "2016-02-18 02:05:00", "duration" => "300"); // 5 mins
$dates[] = array("date" => "2016-02-18 02:10:00", "duration" => "600");
$dates[] = array("date" => "2016-02-18 02:25:00", "duration" => "300");
$dates[] = array("date" => "2016-02-18 02:30:00", "duration" => "600");

$alreadyChosenDates[] = array("date" => "2016-02-18 02:10:30", "duration" => "600"); // 10 mins
//$alreadyChosenDates[] = array("date" => "2016-02-18 02:05:00", "duration" => "300"); // 5 mins

function returnClosestTime($alreadyChosenDates, $dates){
    // Set an array called $closestTime that has the time difference and the key
    $closestTime = [null, null];

    // Check each element in array
    foreach($dates as $key => $date){
        foreach($alreadyChosenDates as $chosenDates){
            // Calculate difference between already chosen dates array and the dates array
            $diff = (strtotime($chosenDates["date"]) + $chosenDates["duration"]) - strtotime($date["date"]);
            if($diff < 0) $diff = $diff * -1; 

            // If $closestTime is empty, populate it
            if($closestTime[0] === null) $closestTime = [$diff, $key];

            // If $closestTime isn't empty and the current date's time difference
            // is smaller, populate $closestTime with the time difference and key
            else if($diff < $closestTime[0]) $closestTime = [$diff, $key];
        }
    }
    return $dates[$closestTime[1]];
}

echo "<pre>";
    print_r(returnClosestTime($alreadyChosenDates, $dates));
echo "</pre>";

输出:

Array
(
    [date] => 2016-02-18 02:25:00
    [duration] => 300
)

在上面的示例中,我只使用了一个已经选择的日期,但我正在寻找一些关于我如何使用两个已经选择的日期的帮助?

所以不要只是这样:

$alreadyChosenDates[] = array("date" => "2016-02-18 02:10:30", "duration" => "600"); // 10 mins

就是这个

$alreadyChosenDates[] = array("date" => "2016-02-18 02:10:30", "duration" => "600"); // 10 mins
$alreadyChosenDates[] = array("date" => "2016-02-18 02:05:00", "duration" => "300"); // 5 mins

并且最接近的日期/时间最接近2016-02-18 02:10:302016-02-18 02:05:00,但也可以查看最近的时间是否位于2016-02-18 02:10:30的中间位置2016-02-18 02:05:00

我将如何做到这一点?

1 个答案:

答案 0 :(得分:2)

我不知道你是否愿意使用OOP方法,但你可以使用这个类:

class ClosestIndicationFinder
{
    protected $indications;
    protected $chosenIndications;

    public function __construct(
        array $indications,
        array $chosenIndications = null
    ) {
        $this->indications = $indications;
        $this->chosenIndications = $chosenIndications;
    }

    public function setChosenIndications(array $chosenIndications)
    {
        $this->chosenIndications = $chosenIndications;

        return $this;
    }

    public function addChosenIndication($indication)
    {
        $this->chosenIndications[] = $indication;

        return $this;
    }

    public function findClosestIndication()
    {
        $this->findAverageChosenIndicationTimestamp();
        $this->findAbsoluteIndicationDifferences();

        return $this->findClosestsIndicationBasedOnDiffs();
    }

    protected $averageChosenTimestamp;
    protected function findAverageChosenIndicationTimestamp()
    {
        $sum = array_reduce(
            $this->chosenIndications,
            function ($sum, $indication) {
                return $sum + $this->calculateIndicationEndTimestamp($indication);
            },
            0
        );

        $this->averageChosenTimestamp = (int) $sum / count($this->chosenIndications);
    }

    protected $diffs;
    protected function findAbsoluteIndicationDifferences()
    {
        $this->diffs = array_map(function ($indication) {
            return abs($this->calculateIndicationsDifference(
                $indication,
                $this->averageChosenTimestamp
            ));
        }, $this->indications);
    }

    protected function calculateIndicationsDifference($indication1, $indication2)
    {
        $timestamp1 = is_array($indication1) 
            ? $this->calculateIndicationBeginningTimestamp($indication1)
            : $indication1;

        $timestamp2 = is_array($indication2) 
            ? $this->calculateIndicationEndTimestamp($indication2) 
            : $indication2;

        return $timestamp1 - $timestamp2;
    }

    protected function calculateIndicationBeginningTimestamp(array $indication)
    {
        return strtotime($indication['date']);
    }

    protected function calculateIndicationEndTimestamp(array $indication)
    {
        return strtotime($indication['date']) + $indication['duration'];
    }

    protected function findClosestsIndicationBasedOnDiffs()
    {
        $closestIndicationIndex = array_search(min($this->diffs), $this->diffs);

        if (!isset($this->indications[$closestIndicationIndex])) {
            return null;
        }

        return $this->indications[$closestIndicationIndex];
    }
}

我试图让方法自我描述,因此代码中没有注释。 OOP方法可以通过扩展类来调整逻辑,只重写那些应该改变行为的方法。例如,我看到了您想要在所选数组中添加新选择日期的其他问题。在类中还有一个方法,但是,我会从初始日期数组中删除所选日期。但由于我只知道最终任务,因此我很难使解决方案完全适合初始任务。

至于多个选定的时间。你写了&#34;但是看看最近的时间是否在&#34; 的中间也是一件好事。如果我错了,请纠正我,但是,如果您想要最接近所选日期的两个日期中间的日期,您可以计算所选日期的平均值并将任务减少到仅查找最近的一个日期。

再一次,如果你能说出你想做什么,可以更准确地解决问题。

顺便说一句,here is working demo