While looping over the rows unconditionally attempt to write or overwrite the word before the identical hour range (if at the string) with the current day of the week. If that replacement attempt fails, append the current day and time range to the end of the string.
This script has the benefit of not needing to pre-group the data and then loop again to present the grouped data. This approach is only an injection or concatenation process. Demo
$data = [
['day' => 'Monday', 'start' => 1100, 'end' => 1300],
['day' => 'Tuesday', 'start' => 1100, 'end' => 1300],
['day' => 'Wednesday', 'start' => 1100, 'end' => 1300],
['day' => 'Thursday', 'start' => 1200, 'end' => 1300],
['day' => 'Friday', 'start' => 1200, 'end' => 1300],
['day' => 'Saturday', 'start' => 1200, 'end' => 1300],
['day' => 'Sunday', 'start' => 1200, 'end' => 1400],
];
function hyphenateConsecutiveDaysWithDuplicateTimes(array $rows): string {
$string = '';
foreach ($rows as $row) {
$time = "({$row['start']}-{$row['end']})";
$string = preg_replace(
"/(?: - [^(]+)?(?= \Q$time\E$)/",
" - {$row['day']}",
$string,
1,
$count
);
if (!$count) {
$string .= ($string ? ', ' : '') . "{$row['day']} $time";
}
}
return $string;
}
echo hyphenateConsecutiveDaysWithDuplicateTimes($data);
The regex pattern:
(?: #start of non-capturing group
- #match space, hyphen, space
[^(]+ #match one or more non-opening-parentheses
)? #end of non-capture group and allow zero or one of the internal match
(?= #start of lookahead
\Q #match space, then tell the engine to treat everything literally
$time #match the parenthetical time range expression
\E #tell the engine to stop treating everything literally
$ #match the end of the string
) #end the lookahead
If the above script isn't pretty or intuitive enough, maybe declare more variables to make it more expressive.
function hyphenateConsecutiveDaysWithDuplicateTimes(array $rows): string {
$string = '';
$optionalEndDay = '(?: - [^(]+)?';
foreach ($rows as $row) {
extract($row);
$time = "($start-$end)";
$sameTimeRange = "(?= \Q$time\E$)";
$string = preg_replace("/$optionalEndDay$sameTimeRange/", " - $day", $string, 1, $count);
if (!$count) {
$string .= ($string ? ', ' : '') . "$day $time";
}
}
return $string;
}
$days_of_week=array("Monday","Tuesday",...,"Sunday");).