Получить список месяцев, начинающийся с данного месяца и заканчивающийся другим?

#php #arrays #loops #range #increment

#php #массивы #циклы #диапазон #увеличить

Вопрос:

Учитывая два целых числа (каждое из которых представляет месяцы в году), мне нужно создать массив целых чисел, который представляет инклюзивный диапазон месяцев между ними.

Чтобы получить номера месяцев между декабрем и февралем, входные данные:

 $start = 12;
$finish = 2;
  

Ожидаемый результат содержит три элемента: 12, 1 и 2 (потому что декабрь, январь, затем февраль)

Я пробовал использовать $arraylist = range($start, $finish); , но когда $start значение больше $finish значения, то на выходе получается неправильный диапазон убывания, подобный этому: [12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2]

Вот еще несколько примеров ввода-вывода:

  -------- --------- ----------------------- 
| $start | $finish |        $output        |
 -------- --------- -----------------------|
|    3   |    11   | [3,4,5,6,7,8,9,10,11] |
 -------- --------- -----------------------|
|   11   |     3   |     [11,12,1,2,3]     |
 -------- --------- -----------------------|
|    3   |     3   |           [3]         |
 -------- --------- ----------------------- 
  

Комментарии:

1. Откуда 1 берется в вашем желаемом выводе?

2. @Nick Я создал массив для количества месяцев, с номером метода 2 для ввода, если начало ввода равно 11, а конец равен 3, то получится [11,12,1,2,3]

3. каков ожидаемый результат, когда начало равно 3, а конец равен 3? Один элемент или тринадцать элементов?

4. @mickmackusa bcs — это количество месяцев, я надеюсь, что возвращаемый результат равен 3, если мы вводим 3 и 3 в качестве диапазона

5. Качество ввода недостаточно для выражения нескольких лет — поскольку ожидается, что входное значение будет между 1 и 12. Если у вас (или у кого-либо еще) другие требования к вопросу, не стесняйтесь задать новый вопрос и указать, как требуется новый метод для расширения функциональности представленных здесь решений. Важно, чтобы объем этого вопроса не уходил в небытие. Это хороший, узкий вопрос, и я надеюсь, что так и останется. Я опечален тем фактом, что этот вопрос получил DVS и был закрыт — я думаю, что в этом сообществе слишком много негатива.

Ответ №1:

Это может быть намного проще, чем уменьшение всего, использование модуля / арифметики и приведение чисел к предпочтительному значению.

  • Цикл, пока два числа не совпадают.
  • Если увеличенное число увеличивается до более чем 12, сбросьте его до 1.
  • Чтобы включить диапазон, вставьте конечный номер в массив.

Код (Демо)

 $array = [];
while ($start != $finish) {
    if ($start > 12) {
        $start = 1;
    }
    $array[] = $start  ;  // increment AFTER pushing into the array
}
$array[] = $finish;
var_export($array);
  

Я думаю, что это менее загадочно для чтения.

Входы / выходы:

 11, 3: [11, 12, 1, 2, 3]

3, 11: [3, 4, 5, 6, 7, 8, 9, 10, 11]

3, 3: [3]
  

p.s. Следующий функциональный стиль также не кажется глупым. Будет либо 1, либо 3 вызова функции, но опять же, я думаю, что это довольно легко читать, и в нем нет цикла, временных переменных и увеличения / уменьшения.

Поскольку объем данных гарантированно будет небольшим, производительность, вероятно, даже не учитывается (ни один человек не заметит разницы в производительности между методами на этой странице). Было бы лучше выбрать метод, который доступен для чтения.

Код: (Демо)

 $array = $start > $finish
    ? array_merge(range($start, 12), range(1, $finish))
    : range($start, $finish);
  

p.p.s. Последнее соображение… Если кто-нибудь предпочтет обрабатывать логику месяца с помощью метода DateTime, это также было бы разумно и может открыть дверь для дальнейшего расширения функциональности (если это когда-либо понадобится задаче). Недостатком является то, что этот метод имеет наибольшие накладные расходы, поскольку он создает экземпляры объектов для работы.

Чтобы выходной массив включал последний месяц, простым решением является добавление 1 к концу. Если $begin значение меньше $finish значения, то мы перенесем значение на следующий год, добавив 12.

Код: (Демо)

 $begin = 11;
$finish = 3;

$period = new DatePeriod(
    DateTime::createFromFormat('m', $begin),
    new DateInterval('P1M'),
    DateTime::createFromFormat('m', $finish   ($begin > $finish ? 13 : 1))
);

foreach ($period as $obj) {
    $array[] = $obj->format('n');
}

var_export($array);
  

Ответ №2:

Один из способов сделать это — использовать арифметику по модулю 12. Сначала преобразуйте $start и $finish в диапазон 0-11, вычитая единицу, затем увеличьте $start и переместите в массив (преобразуя обратно в диапазон 1-12, как вы делаете) до $start == $finish :

 $start = 12;
$finish = 2;

$arraylist = array();
$start = --$start;
$finish = --$finish;
while ($start != $finish) {
    $arraylist[] =   $start;
    $start = $start % 12;
}
$arraylist[] =   $start;
print_r($arraylist);
  

Вывод:

 Array
(
    [0] => 12
    [1] => 1
    [2] => 2
)
  

Демонстрация на 3v4l.org