Итерация по поддиапазону дней недели

Я пытаюсь перебрать диапазон дней недели, где каждый день недели соответствует целому числу (Sunday = 1, Monday = 2, ..., Saturday = 7).

Диапазон определяется start and end day. Это нормально для начального и конечного дня, например Monday(2) - Thursday(5), так как я могу просто сделать:

for(int i = startDay; i <= endDay; i++) { ... } 

У меня возникают трудности, когда диапазон делится на конец и начало недели, например Friday(6) - Monday(2). Это, очевидно, не работает с указанным выше циклом for - например.

for(int i = 6; i <= 2; i++) { ... }    // wouldn't even execute once. 

Единственное решение, которое я вижу, — это реализация своего рода циклического буфера, который, как мне кажется, излишен для такой простой проблемы. Я просто в тупике и, скорее всего, здесь не хватает чего-то очевидного. Я думаю, что решение может иметь какое-то отношение к модульной арифметике, но я не совсем уверен.


person Kumalh    schedule 17.04.2014    source источник


Ответы (4)


Ты можешь сделать:

int numberOfDays = endDay >= startDay ? endDay - startDay : 8 - (startDay - endDay);
for (int i = startDay; i <= startDay + numberOfDays; i++) {
    int day = (i - 1) % 7 + 1;
}

Это использует оператор по модулю %, чтобы гарантировать, что все значения остаются в пределах от 1 до 7.

Например, когда i станет равным 8, вычисление вернет day обратно к 1: (8 - 1) % 7 + 1 == 1.

person Simeon Visser    schedule 17.04.2014
comment
Учитывая такой диапазон, как startDay = 6 and endDay = 3, не будет ли это вообще выполняться? startDay + (endDay - startDay) = 6 + (3 - 6) = 3 Результат: for(int i = 6; i <= 3; i++) { ... } Что не будет выполнено? - person Kumalh; 17.04.2014
comment
Должно ли быть ... 7 - (startDay - endDay);, а не ... 8 - (startDay - endDay);? В противном случае он всегда будет добавлять один дополнительный день. - person Kumalh; 17.04.2014
comment
Это зависит от того, что вы хотите, и от того, включен ли последний день в диапазон. - person Simeon Visser; 17.04.2014

Вероятно, проще всего использовать break, тогда вам не нужно беспокоиться обо всех разных случаях:

for (int day = startDay; ; day = (day - 1) % 7 + 1) {
    // ... do your stuff
    if (day == endDay) {
        break;
    }
}

или, некоторые могут предпочесть это:

int day = startDay;
while (true) {
    // ... do something
    if (day == endDay) {
        break;
    }
    day = (day - 1) % 7 + 1;
}

or:

int day = startDay;
while (true) {
    // ... do something
    if (day == endDay) {
        break;
    }
    if (++day > 7) {
        day = 1;
    }
}

Попытка правильно разобраться во всех случаях с помощью цикла for может оказаться головной болью. Вы должны убедиться, что они обработаны:

startDay == 1, endDay == 7
endDay == startDay
endDay == startDay - 1  (which should go through every day of the week in some order)
endDay > startDay
endDay < startDay
person ajb    schedule 17.04.2014

В Java 8:

// input section
DayOfWeek start = DayOfWeek.FRIDAY;
DayOfWeek end = DayOfWeek.MONDAY;

// execution section
DayOfWeek dow = start;
DayOfWeek stop = end.plus(1);

do {
  // ... your code
  dow = dow.plus(1);
} while (dow != stop);

Конструкция do-while гарантирует, что для условия start == end цикл будет выполнен хотя бы один раз.

ОБНОВЛЕНО в связи с использованием ваших локализованных индексов (воскресенье = 1 вместо 7)

Вы можете преобразовать индексы в DayOfWeek-объекты следующим образом:

private static DayOfWeek convert(int localIndex) {
  int iso = localIndex - 1;
  if (iso == 0) {
    iso = 7;
  }
  return DayOfWeek.of(iso);
}
person Meno Hochschild    schedule 17.04.2014

Вы можете использовать оператор % для какой-то цикличности

 for (int i=6; i!=2; i=(i+1)%7) { ... }

Это будет индексировать дни с 0, поэтому воскресенье = 0 ... суббота = 6. Если вы действительно хотите, чтобы индекс начинался с 1, это только проблема интерпретации. Вы можете, например, сделать:

 for (int i=6; i!=2; i=(i+1)%7) { 
     int day=i+1; 
     // use day here
 }
person damgad    schedule 17.04.2014
comment
Как это можно изменить, чтобы не индексировать дни с 0? то есть учитывая startDay = 6 and endDay = 3, я бы хотел посмотреть только на день 6, 7, 1, 2, 3. Не day 0 - person Kumalh; 17.04.2014