For a rent application, I have an array $dates like this:
Array
(
[2013-07-19] => 1
[2013-07-21] => 3
[2013-07-23] => 2
[2013-07-24] => 4
[2013-07-25] => 4
[2013-07-26] => 2
[2013-07-27] => 2
[2013-07-30] => 3
[2013-07-31] => 1
)
The date is the key, and the values are the number of items rent in that day for a specific product
How can I split this array in many sub arrays containing each a list of consecutive days? Like this:
Array
(
[0] => Array
(
[2013-07-19] => 1
)
[1] => Array
(
[2013-07-21] => 3
)
[2] => Array
(
[2013-07-23] => 2
[2013-07-24] => 4
[2013-07-25] => 4
[2013-07-26] => 2
[2013-07-27] => 2
)
[3] => Array
(
[2013-07-30] => 3
[2013-07-31] => 1
)
)
you can do it like this:
$data = array(
'2013-07-19' => 1,
'2013-07-21' => 3,
'2013-07-23' => 2,
'2013-07-24' => 4,
'2013-07-25' => 4,
'2013-07-26' => 2,
'2013-07-27' => 2,
'2013-07-30' => 3,
'2013-07-31' => 1
);
$result = array();
// choose a fake old date or the first date from $data
$ref = new DateTime('1821-11-11');
foreach ($data as $datum => $nb) {
// compare $ref + 1 day with $datum (the current item date)
if ($ref->modify('+1 day')->format('Y-m-d') !== $datum) {
$result[] = array();
$ref = new DateTime($datum);
}
$result[count($result) - 1][$datum] = $nb;
}
print_r($result);
Notices:
starting with PHP 7.3, you can easily extract the first key of the $data
array to create the first reference date using array_key_first
(instead of using a fake old date):
$ref = new DateTime(array_key_first($data));
You can also use the combo reset
+ key
for older versions, it doesn't matter since the foreach
loop will reset the array pointer immediately after.
If you want to avoid the creation of a new DateTime instance each time there is a jump between dates ($ref = new DateTime($datum);
), you can choose to only set the already existing instance with:
$ref->setDate(...explode('-', $datum));
(Not sure it will give you a great advantage in terms of readability or performance, but it's a possibility.)