Здравствуйте, netch80, Вы писали:
N>Это всё очевидно. Неочевидно сходу то, насколько скоро он это всё забудет — а если такая идиома встречается не часто, то забудет быстро.
Ну не запомнит юниор с первого раза, в чём трагедия?
N>>>Имеет, да. Но читаешь всё равно шаблонами. И шаблон типа for i in closed_range(n-1, 0, -1) будет читаться проще всегда, чем while(n--).
EP>>Да и что означает closed_range в данном случае? запрет на n=0?
N>Наоборот, что оба граничных значения включены в набор.
Ну то есть ты действительно имеешь в виду стандартное значение closed, а не какое-то своё, а значит [n-1, 0] так?
n=1: [0, 0]
n=0: [-1, 0]
Зато смотри как стройно с
while(n--): (n, 0]
N>Closed — оба конца включены. Open — оба конца не включены.
N>Half-open range — например, в C++ для любого контейнера begin() входит в значения, а end() — нет. В Python, аналогично, range(0, 10) это от 0 до 9 включительно (а чтобы от N до M включительно вниз, надо писать range(N, M-1, -1)).
Ну так в C++ он half-open, как раз для того чтобы пустые диапазоны можно было определять: [first, first).
Как ты пустой диапазон обозначишь на closed range? [first, first] не работает
На Python он тоже half-open.
А у тебя closed_range(x, y, -1) — это что? [x, y]?
EP>>Ну я говорю всё время про while(n--), но можем конечно и вариант с for погрепать. Но суть от этого не меняет — применяется повсеместно.
N>Вот именно что "повсеместность" этого подхода, как оказывается, сильно однобока.
Что значит однобока? Само по себе итерирование вниз нужно очень редко, по моим прикидкам один к ста или даже один к тысячи по сравнению с итерированием вверх
EP>>Да, сам увидел — я это место дополнил:
EP>>Точнее one-before-last обходится переносом декремента на первую строчку тела (как уже показывали ранее в этой теме): while(it != first){--it; ...}, но концептуально то же самое.
N>Ну и снова получаем уже известную проблему: надо перед циклом начать с n+1, чтобы в цикле работать с n. Это уже второй уровень наворота идиомы (первый — формат условия продолжения с пост-декрементом).
Да не нужно начинать с n+1, оно уже "готовое" — итератор .end() — уже указывает на один за последним элементом.
То есть для стандартных [first, last) получаем:
while(last != first){--last; use(*last); }, никаких преикрементов.
Точно также как для N элементов последний индекс начиная от 0 — N-1, поэтому не нужно делать N+1 перед циклом
N>>>Оптимизатор всё равно для типовых случаев вроде плоского массива всё это заоптимизирует.
EP>>Не всегда варианты простые. Тем не менее — прямее сразу делать оптимально по-возможности жеж.
N>Так не оптимально же, когда лишний инкремент на входе
Так его и нету