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