LoginSignup
3
2

More than 5 years have passed since last update.

連続した数列を範囲形式にまとめたい をPHPで - その2

Last updated at Posted at 2014-03-01

前回のコードでは対象が数値配列固定だったので、データ構造とアルゴリズムを分離してアルゴリズムを再利用できるようにする。

<?php

class ContinuousRangeDivider
{
    public function divide($data, $continuousChecker)
    {
        return array_reduce($data, function ($current, $element) use ($continuousChecker) {
            if (count($current) == 0) {
                $current[] = [$element];
                return $current;
            }

            $currentLastRange = end($current);
            $currentLastNumber = end($currentLastRange);
            if ($continuousChecker($currentLastNumber, $element)) {
                if (count($currentLastRange) > 1) {
                    array_pop($currentLastRange);
                }
                $currentLastRange[] = $element;
                array_pop($current);
                $current[] = $currentLastRange;
            } else {
                $current[] = [$element];
            }
            return $current;
        }, []);
    }
}

class ContinuousRangesPrinter
{
    public function render($ranges, $toString = null)
    {
        if (!$toString) {
            $toString = function ($input) {
                return $input;
            };
        }
        return array_reduce($ranges, function ($current, $range) use ($toString) {
            if ($current != '') {
                $current .= ',';
            }

            $current .= $toString($range[0]);

            if (count($range) > 1) {
                $current .= '-' . $toString($range[1]);
            }

            return $current;
        }, '');
    }
}

$divider = new ContinuousRangeDivider();
$printer = new ContinuousRangesPrinter();


// 数値配列
$data = [1, 3, 4, 5, 7];
$ranges = $divider->divide($data, function ($a, $b) {
    return ($b - $a) == 1;
});
echo $printer->render($ranges),PHP_EOL;


// 日付配列
$data = [
    new \DateTime('2014-01-01'),
    new \DateTime('2014-01-02'),
    new \DateTime('2014-01-13'),
    new \DateTime('2014-01-14'),
    new \DateTime('2014-01-15'),
    new \DateTime('2014-01-31'),
    new \DateTime('2014-02-01'),
];
$ranges = $divider->divide($data, function ($a, $b) {
    return ($b->getTimestamp() - $a->getTimestamp()) == 86400;
});
echo $printer->render($ranges, function ($input) {
    return $input->format('n/j');
}),PHP_EOL;


// 結果
// 1,3-5,7
// 1/1-1/2,1/13-1/15,1/31-2/1
3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2