Timeword - сжать массив дней и представить его как набор диапазонов - PullRequest
0 голосов
/ 10 мая 2011

Я пытаюсь сделать функцию, которая будет принимать этот ввод: mon,tue,wed,thu,fri,sat

и выплевывать это: mon-sat

В данный момент я использую это.

function dayrange($days){
   $days = explode(",", str_replace(" ","",$days));
   return reset($days) . "-" . end($days);
}

Хорошо, теперь для кривого шара, я хочу, чтобы функция также работала, если я дам ей эту строку: mon,tue,wed,fri,sat

Необходимо пропустить четверг и сказать что-то вроде:ср, пт-сб

Могу ли я получить рекомендации о том, как лучше всего это сделать?Я использую PHP, поэтому ответы в php великолепны, но код psuedo тоже подойдет.

Cheers

Ответы [ 2 ]

3 голосов
/ 10 мая 2011

По сути, я бы подошел к этому:

  1. Преобразование дней в соответствующие числовые значения
  2. Превращение массива чисел в строку с диапазонами
  3. Преобразованиечисла в строке обратно в дни недели

Я написал некоторый код для этого:

/**
 * Convert an array of numbers to a string containing ranges and single values
 * @param array $numbers an array of numbers
 * @return string
 */
function compressNumbers($numbers) {
    $result = array();
    sort($numbers);
    $previousValue = reset($numbers);
    $startValue = $previousValue;
    foreach ($numbers as $value) {
        if ($value > $previousValue + 1) {
            if ($startValue == $previousValue) {
                $result[] = $startValue;
            } else {        
                $result[] = $startValue . '-' . $previousValue;
            }
            $startValue = $value;
        }
        $previousValue = $value;
    }
    if ($startValue == $previousValue) {
        $result[] = $startValue;
    } else {        
        $result[] = $startValue . '-' . $previousValue;
    }
    return implode(',', $result);
}

/*
 * Creates an array with values the three letter representation for days of the 
 * week and keys the corresponding numeric representation.
 *
 * @return array
 */
function createLookupNumberToDay() {
    $date = strtotime('now');
    $lookup = array();
    for ($i = 1; $i <= 7; $i++) {
        $lookup[date('w', $date)] = date('D', $date);
        $date = strtotime('+1 day', $date);
    }
    return $lookup;
}

/*
 * Converts a string listing days separated by commas into 
 * an array with values the numeric value for the corresponding
 * day of the week.
 *
 * @param string $days
 * @return array
 */
function convertDaysToNumbers($days) {
    $result = array();
    $daysArray = explode(",", str_replace(" ","",$days));
    foreach ($daysArray as $day) {
        $result[] = date('w', strtotime($day));
    }
    return $result;
}

/*
 * Converts the numbers in a string to the corresponding 3-letter day of the
 * week abbreviation.
 *
 * @param string $string
 * @return string
 */
function convertNumbersToDays($string) {
    $lookup = createLookupNumberToDay();
    return str_replace(array_keys($lookup), $lookup, $string);
}

function convert($string) {
    return (convertNumbersToDays(compressNumbers(convertDaysToNumbers($string))));
}

echo convert('mon,tue,wed,thu,fri,sat');
echo '<br />';
echo convert('mon,tue,wed,sat');
echo '<br />';
1 голос
/ 10 мая 2011

Не проверял это, но должно дать вам хорошее начало. Он также обрабатывает недельные упаковки.

function dayrange($days){
    $wdays = array("mon","tue","wed","thu","fri","sat","sun");

    $indays = explode(",", str_replace(" ","",$days)); // expand the list to an array


    $retstr = array_shift($indays); // get the first date

    $curpos = array_search($retstr, $wdays);  // current position in the wdays array
    $intv = 0;    // interval between days to avoid mon-tue like output

    foreach($indays as $d) {
       if($d == $wdays[$curpos]) {
          $curpos = ($curpos++) % 7; // this will take care of wrapping.
          $intv++;
       } else {
           $retstr.= ($intv > 1 ? "-".$d:",".$d); // use appropriate join
           $intv = 0; // reset interval
       }
    }
    if($intv > 0) {   // if anything was left deal with the end.
        $retstr.= ($intv > 1 ? "-".$d:",".$d);
    } else {
        $retstr.= ",".$d;
    }
    return ($retstr);
}
...