Day Sequence Display

Let's say I have these arrays of numbers that correspond to the days of the week (starting on Monday):

/* Monday - Sunday */ array(1, 2, 3, 4, 5, 6, 7) /* Wednesday */ array(3) /* Monday - Wednesday and Sunday */ array(1, 2, 3, 7) /* Monday - Wednesday, Friday and Sunday */ array(1, 2, 3, 5, 7) /* Monday - Wednesday and Friday - Sunday */ array(1, 2, 3, 5, 6, 7) /* Wednesday and Sunday */ array(3, 7) 

How can I efficiently convert these arrays to the desired strings, as shown in the C style comments? Any help would be greatly appreciated.

+7
date php days
source share
4 answers

The following code should work:

 <?php // Create a function which will take the array as its argument function describe_days($arr){ $days = array("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"); // Begin with a blank string and keep adding data to it $str = ""; // Loop through the values of the array but the keys will be important as well foreach($arr as $key => $val){ // If it's the first element of the array or ... // an element which is not exactly 1 greater than its previous element ... if($key == 0 || $val != $arr[$key-1]+1){ $str .= $days[$val-1]."-"; } // If it's the last element of the array or ... // an element which is not exactly 1 less than its next element ... if($key == sizeof($arr)-1){ $str .= $days[$val-1]; } else if($arr[$key+1] != $val+1){ $str .= $days[$val-1]." and "; } } // Correct instances of repetition, if any $str = preg_replace("/([AZ][az]+)-\\1/", "\\1", $str); // Replace all the "and"s with commas, except for the last one $str = preg_replace("/ and/", ",", $str, substr_count($str, " and")-1); return $str; } var_dump(describe_days(array(4, 5, 6))); // Thursday-Saturday var_dump(describe_days(array(2, 3, 4, 7))); // Tuesday-Thursday and Sunday var_dump(describe_days(array(3, 6))); // Wednesday and Saturday var_dump(describe_days(array(1, 3, 5, 6))); // Monday, Wednesday and Friday-Saturday ?> 
+3
source share
 /* Monday - Sunday */ $days1 = [1, 2, 3, 4, 5, 6, 7]; /* Monday - Wednesday and Sunday */ $days2 = [1, 2, 3, 7]; /* Wednesday and Sunday */ $days3 = [3, 7]; /* Monday - Wednesday and Friday - Sunday */ $days4 = [1, 2, 3, 5, 6, 7]; /* Monday - Wednesday, Friday and Sunday */ $days5 = [1, 2, 3, 5, 7]; /* Monday, Wednesday, Friday and Sunday */ $days6 = [1, 3, 5, 7]; // creates logic groups out of flat array function splitIntoSequences(array $days) { $collection = []; do { $seq = extractSequence($days); $collection[] = $seq; $days = array_diff($days, $seq); } while (!empty($days)); return $collection; } // filters the next sequence function extractSequence(array $days) { sort($days); $seq = []; foreach ($days as $day) { // seq break if (!empty($seq) && $day - 1 != $seq[count($seq) - 1]) { return $seq; } $seq[] = $day; } return $seq; } // removes all unneeded steps from sequences function cleanupSequences(array $collection) { $cleanedCollection = []; foreach ($collection AS $seq) { if (count($seq) == 1) { $cleaned = [array_pop($seq)]; } else { $cleaned = [array_shift($seq), array_pop($seq)]; } $cleanedCollection[] = $cleaned; } return $cleanedCollection; } // convert whole collection to daynames function convertToDaynames(array $collection) { $daynameCollection = []; foreach ($collection AS $seq) { $days = []; foreach ($seq as $day) { $days[] = numberToDay($day); } $daynameCollection[] = $days; } return $daynameCollection; } // number to dayname function numberToDay($weekday) { $relative = sprintf('next Sunday + %d day', $weekday); $date = new \DateTime($relative); return $date->format('l'); } // format output function format(array $collection) { $t = []; foreach ($collection as $seq) { $t[] = implode(' - ', $seq); } if (count($t) == 1) { return array_pop($t); } $last = array_pop($t); return sprintf('%s and %s', implode(', ', $t), $last); } 

Call Testing:

 function makeMeHappy(array $seq) { $splitted = splitIntoSequences($seq); $cleaned = cleanupSequences($splitted); $daynames = convertToDaynames($cleaned); return format($daynames); } var_dump(makeMeHappy($days1)); // string(15) "Monday - Sunday" var_dump(makeMeHappy($days2)); // string(29) "Monday - Wednesday and Sunday" var_dump(makeMeHappy($days3)); // string(20) "Wednesday and Sunday" var_dump(makeMeHappy($days4)); // string(38) "Monday - Wednesday and Friday - Sunday" var_dump(makeMeHappy($days5)); // string(37) "Monday - Wednesday, Friday and Sunday" var_dump(makeMeHappy($days6)); // string(36) "Monday, Wednesday, Friday and Sunday" 
+3
source share

I tried and tested this:

 /* Monday - Sunday */ $days1 = array(1, 2, 3, 4, 5, 6, 7); /* Monday - Wednesday and Sunday */ $days2 = array(1, 2, 3, 7); /* Wednesday and Sunday */ $days3 = array(3, 7); /* Monday - Wednesday and Friday - Sunday */ $days4 = array(1, 2, 3, 5, 6, 7); /* Monday - Wednesday, Friday and Sunday */ $days5 = array(1, 2, 3, 5, 7); /* Monday, Wednesday, Friday and Sunday */ $days6 = array(1, 3, 5, 7); function displayDays($days = array()) { // 1: Create periods and group them in arrays with starting and ending days $periods = array(); $periodIndex = 0; $previousDay = -1; $nextDay = -1; foreach($days as $placeInList => $currentDay) { // If previous day and next day (in $days list) exist, get them. if ($placeInList > 0) { $previousDay = $days[$placeInList-1]; } if ($placeInList < sizeof($days)-1) { $nextDay = $days[$placeInList+1]; } if ($currentDay-1 != $previousDay) { // Doesn't follow directly (in week) previous day seen (in our list) = starting a new period $periodIndex++; $periods[$periodIndex] = array($currentDay); } elseif ($currentDay+1 != $nextDay) { // Follows directly previous day, and isn't followed directly (in week) by next day (in our list) = ending the period $periods[$periodIndex][] = $currentDay; $periodIndex++; } } $periods = array_values($periods); // Arrived here, your days are grouped differently in bidimentional array. // print_r($periods); // If you want to see the new array structure // 2: Display periods as we want. $text = ''; foreach($periods as $key => $period) { if ($key > 0) { // Not first period if ($key < sizeof($periods)-1) { // Not last period either $text .= ', '; } else { // Last period $text .= ' and '; } } if (!empty($period[1])) { // Period has starting and ending days $text .= jddayofweek($period[0]-1, 1).' - '.jddayofweek($period[1]-1, 1); } else { // Period consists in only one day $text .= jddayofweek($period[0]-1, 1); } } echo $text.'<br />'; } displayDays($days1); displayDays($days2); displayDays($days3); displayDays($days4); displayDays($days5); displayDays($days6); 

jddayofweek() returns the day of the week. In this function, 0 is Monday, 6 is Sunday, so "-1" is here every time I use it: your Monday is 1, and your Sunday is 7.

+2
source share

We can transfer the problem with the array to the problem with the string and use a regular expression (regular expression) ... Indirectly, it checks all conditions and cases on state machines .

PS: when we have short arrays and a small number of cases, such an algorithm design is safe and offers a complete solution.

Oh yes, we can also translate week numbers into other languages ​​(see the $ lang parameter)!

Multilingual and regular expression

 function weekNumbers_toStr($days, $lang='en') { $and = array('pt'=>'e', 'en'=>'and'); $strWeek = array( // config with more langs! 'pt'=>array("Segunda", "TerΓ§a", "Quarta", "Quinta", "Sexta", "SΓ‘bado", "Domingo"), 'en'=> array("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday") ); $days = array_unique($days); sort($days); $seq = preg_replace_callback( // Split sequence by ",": '/0246|024|025|026|135|146|246|02|03|04|05|06|13|14|15|16|24|25|26|35|36|46/', function ($m) { return join( ',' , str_split($m[0]) ); }, join('',$days) ); // split two or more days by "-": $seq = preg_replace('/(\d)\d*(\d)/', '$1-$2', $seq); $a = explode(',',$seq); $last = array_pop($a); $n = count($a); // Formating and translating: $seq = $n? join(", ",$a): $last; if ($last && $n) $seq = "$seq $and[$lang] $last"; return preg_replace_callback( '/\d/', function ($m) use (&$strWeek,$lang) { return $strWeek[$lang][$m[0]]; }, $seq ); } // func 

Testing:

 print "\n".weekNumbers_toStr(array(6,1,2,3,6),'en'); // corrects order and dups print "\n".weekNumbers_toStr(array(0,1,2,3,6)); // Monday-Thursday and Sunday print "\n".weekNumbers_toStr(array(3,4,6),'pt'); // Quinta-Sexta e Domingo print "\n".weekNumbers_toStr(array(3,4,6)); // Thursday-Friday and Sunday print "\n".weekNumbers_toStr(array(2,3,4,6)); // Wednesday-Friday and Sunday print "\n".weekNumbers_toStr(array(3,5)); // Thursday and Saturday print "\n".weekNumbers_toStr(array(0,2,4,6)); // Monday, Wednesday, Friday and Sunday print "\n".weekNumbers_toStr(array(0)); // Monday print "\n".weekNumbers_toStr(array()); // (nothing) 
+2
source share

All Articles