Re: Просидев на одном предприятии несколько лет...
От: _FRED_ Черногория
Дата: 06.08.21 13:47
Оценка: 3 (1) :))) :))) :))) :))) :))) :)))
Здравствуйте, vaa, Вы писали:

vaa>https://habr.com/ru/post/571342/


Так в исходниках табы же! Автору повезло что, хоть, не побили :о))

  Поехал я как-то в отпуск…
…и во время отдыха хорошо так прилетело мне из-за моей собственной неуклюжести тяжёлой деревянной рамой от окна прямо в глаз, синяк получился смачный. Когда пришёл в офис, коллег заинтересовало это украшение, а мне до того обидно было рассказывать как всё случилось на самом деле, что я каждый раз придумывал новую историю. Одна из них была про собеседование:

В отпуске я был за границей и, уже отдохнув и начав скучать, решил сходить на собеседование. Пришёл, поговорили о том, о сём, попросили меня на доске написать код одной не сложной операции. Я написал. Один из собеседующих смотрит так внимательно на доску и вдруг спрашивает: а что это у вас тут в коде пробелами отступы сделаны, а не удобными табами? А я ему: да ну что вы, какие табы, XXI век на дворе. пробелы наши всё! Вот так, слово-заслово, мы и подрались
Help will always be given at Hogwarts to those who ask for it.
Re: Просидев на одном предприятии несколько лет...
От: кубик  
Дата: 06.08.21 10:25
Оценка: +8 :))
Ничего улыбательного здесь нет, это просто "О работе".
Не стоит идти в фирму где пишут "задание Вы выполнили действительно отвратительно, халтурно". Это хамство.
Надо идти где отвечают вежливо: "Спасибо за Ваше потраченое время и желание работать в нашей фирме! В настоящее время нам бы хотелось найти человека с бОльшим опытом в данной технологии. Благодарим Вас еще раз и Желаем успехов в вашем профессиональном пути!"
Re[2]: Просидев на одном предприятии несколько лет...
От: Doom100500 Израиль  
Дата: 11.08.21 05:35
Оценка: +6 :)
Здравствуйте, scf, Вы писали:

scf>На хабре выложили интересный разбор решения и предложили "как надо" https://habr.com/ru/post/572052/


А давайте ещё что-нибудь переусложним в тестовом задании на день.
Спасибо за внимание
Re[3]: Просидев на одном предприятии несколько лет...
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 11.08.21 08:53
Оценка: 1 (1) +5
Здравствуйте, vaa, Вы писали:

vaa>Здравствуйте, scf, Вы писали:


scf>>На хабре выложили интересный разбор решения и предложили "как надо" https://habr.com/ru/post/572052/


vaa>Мне одному кажется, что "как надо" не лучше, чем "как получилось" по большому счёту?


Автор "как надо" захотел попонтоваться монадами и парсерами, которые в итоге занимают примерно столько же, сколько рукопашный парсинг и работает в разы медленнее. ИИ до сих пор не пойму чем регулярки не угодили?

Кроме того автор "как надо" забил на оптимизацию, и у него каждый Schedule будет занимать 100+12+32+7+24+60+60+1000 байт. Хоть бы bitarray\bitvector32 использовал для приличия. Или разворачивал бы этот длинный списко только на время поиска.
Re: Просидев на одном предприятии несколько лет...
От: Mr.Delphist  
Дата: 06.08.21 17:52
Оценка: 8 (3) +2
Здравствуйте, vaa, Вы писали:

vaa>https://habr.com/ru/post/571342/

vaa>Читаю комменты второй день и . Парадоксально на мой взгляд, но никто до сих пор(региться не охота)
vaa>не отметил:
vaa>1. быть может отказали почуяв крутого кулцхакера(конкурента).
vaa>слышал в крупных компаниях есть такое ограничение — слишком умных не брать, чтобы не взломали систему.
vaa>2. "Просидев на одном предприятии несколько лет...", таки зачем срываться? похоже на минутную слабость.
vaa>3. почему-то все крутые прогеры пока только накидывают критики, но никто не показал образцовое решение.

Таки глянул код — статья получилась резонансная, сыпется из разных мест ленты, пришлось читать. Ну и что могу сказать: я бы тоже не взял. Ровно по той же причине, почему не взял бы себя-раннего с точки зрения себя-сегодняшнего.

1) Всё врукопашку. Человек вроде не новичок, и даже знает про RegExp, но в итоге вся работа по парсингу входной строки — через простыню IndexOf. Не то что токенайзер или Linq, даже обычный Split отсутствует.
Чем это плохо: случись изменение в формате строки -> старый код в утиль, целиком. Со всеми юнит-тестами и бенчмарками.

2) Длинные методы, многоуровневые if. По сути, продолжение предыдущего пункта. Читая такой код, понимаешь, что имеешь дело с эдаким C#-ассемблером, дампом мыслленного решения, существующего в голове автора.
Чем это плохо: приходится "дизассемблирвоать" эту простыню, чтобы понять, какую проблему решает код, почему в этот if зайти надо, а в следующий — нет. Потому что настоящий "исходник" — так и остаётся в голове автора. Телепатию пока не завезли, увы. Ну и как говорилось выше — цена изменений.

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

Выводы:
1) Надо уметь не только язык (это обычно самое простое), но и инфраструктуру прикладных библиотек вокруг него.
2) Работа в команде — отдельный вид деятельности, и он необходим хотя бы как этап проф-развития, каким бы гением ты ни был.
3) If at first you don't succeed, try, try again.
Re[3]: Просидев на одном предприятии несколько лет...
От: Doom100500 Израиль  
Дата: 10.08.21 05:15
Оценка: +4
Здравствуйте, mgu, Вы писали:

mgu>
mgu>    if (((_days[t1.Day - 1] > 0) || (isLastDayInMonth && (_days[31] > 0))) && (_weekDays[(int)t1.DayOfWeek] > 0))
mgu>


mgu>Приоритет математических операций изучают во втором классе школы. Судя по правописанию, автор закончил только первый.


Это не математические, а логические оперзции. В школе их не изучают (по крайней мере не во втором классе).
А ставить скобки для удобочтаемости — это нормально.
Спасибо за внимание
Re[3]: Просидев на одном предприятии несколько лет...
От: elmal  
Дата: 11.08.21 08:15
Оценка: 5 (1) +2
Здравствуйте, vaa, Вы писали:

vaa>Это много? тут чуть выше написали появился альтернативный вариант, который "намного" лучше

vaa>но спустя 5 дней.
Во первых там не все 5 дней на фултайме делали. Уверен что на альтернативный вариант максимум час потратили, ибо неимоверно лень. А во вторых, вот такую лютую жуть, который в коде у автора, нельзя ни в коем случае писать вообще никогда, как бы не горели сроки. Ибо потом если он сотворит багу, то искать он ее будет очень долго. Вот именно сейчас пишу лютую жуть, которая должна быть неимоверно оптимизирована, ибо узкое место, и где до черта всяких краеугольных камней. Так я сначала добиваюсь чтоб проходили тесты, делаю чтоб код был максимально читаемый и я сам там не помер. И только после того, как тесты все пройдут, плюс я прогоню вообще тесты на всех данных — только тогда я буду уже делать финальную оптимизацию, при этом еще и бенчмаркая. Финальная оптимизация — это я заменю обход через рекурсию на тупо цикл, предполагая пока голословно, что это будет быстрее. И потом на финальном этапе мне придется вместо одного общего случая писать для разных случаев специализированные копипасты. Если б я сразу хреначил тем жутким спагетти, которое возможно получится на выходе, я бы от багов в процессе отладки помер бы и вряд ли бы к новому году закончил.
Re: Просидев на одном предприятии несколько лет...
От: nikkit  
Дата: 06.08.21 03:54
Оценка: 2 (1) +2
vaa>2. "Просидев на одном предприятии несколько лет...", таки зачем срываться? похоже на минутную слабость.

не знаю как насчет у всех, но у людей имеет место такое явление, как выгорание. знаю по себе. в этом случае и себя насилуешь и проекту пользу перестаешь приносить. выход вижу один — валить и длительный отпуск. тогда только отпускает.
Re: Просидев на одном предприятии несколько лет...
От: CEMb  
Дата: 06.08.21 08:04
Оценка: 2 (2) +1
Здравствуйте, vaa, Вы писали:

vaa>https://habr.com/ru/post/571342/


автор статьи хороший специалист, как я понял из его подхода к делу. Это без шуток.

vaa>Читаю комменты второй день и . Парадоксально на мой взгляд, но никто до сих пор(региться не охота)

vaa>не отметил:
vaa>1. быть может отказали почуяв крутого кулцхакера(конкурента).
vaa>слышал в крупных компаниях есть такое ограничение — слишком умных не брать, чтобы не взломали систему.
Там было первым пунктом: хотят взять джуна на кикинга (англ. мальчика для битья). Хороший технический специалист в угол не загоняется ни при каких условиях. Если только сам не накосячил. Даже если и сам накосячил. Тем более, если сам накосячил.

vaa>2. "Просидев на одном предприятии несколько лет...", таки зачем срываться? похоже на минутную слабость.

Человек так устроен, что хочет попробовать все альтернативы. Особенно человек мужского пола, но это уже детали. Как люди говорят: лучше попробовать и пожалеть, чем не попробовать и пожалеть. Ну вот эта формула всегда срабатывает, когда подворачивается случай. Да и вообще нужно двигаться и развиваться. Ну или хотя бы просто двигаться.

vaa>3. почему-то все крутые прогеры пока только накидывают критики, но никто не показал образцовое решение.

Вот, кстати, чем крутой прогер отличается от простого:
— Крутой прогер никогда не тратит время на доказательства того, что он крутой прогер.
— Крутой прогер знает, что образцовые решения бывают только для образцовых задач. Как сферический конь для цилиндричкой лошади вакуума.
— Крутой прогер пришет только то, что нужно для дела. Поэтому некоторые по незнанию удивляются крутым прогерам, которые долго ничего не пишут.
— Крутой прогер, к тому же, не станет лезть в код и выдавать критику, он и так всё поймёт, пообщавшись с крутым прогером, как я это сделал в первой строчке. Ну в самом деле, вы же не разбираете компьютер на запчасти, чтобы понять, как хорошо он работает? Если только вы сам не компьютер, тогда можно. А так вам просто нужно увидеть его в процессе работы, и всё станет ясно.
Re[2]: Просидев на одном предприятии несколько лет...
От: mgu  
Дата: 10.08.21 02:03
Оценка: +1 -1 :)
Здравствуйте, B0FEE664, Вы писали:

vaa>>3. почему-то все крутые прогеры пока только накидывают критики, но никто не показал образцовое решение.

BFE>Какой самобытный код!
BFE>Я очарован этим кодом.
BFE>
  Опасно! Не для слабых умов. При чтении можно заработать вывих мозга:
BFE>
BFE>using System;

BFE>namespace TestApp
BFE>{
BFE>    /// <summary>
BFE>    /// Класс для задания и расчета времени по расписанию.
BFE>    /// </summary>
BFE>    public class Schedule
BFE>    {
BFE>        private const string _placeholder = "*"; // Звездочка означает любое возможное значение.
BFE>        private const string _defaultMilliseconds = "0"; // fff - миллисекунды (0-999). Если не указаны, то 0

BFE>        internal readonly byte[] _years =        new byte[101]; // год (2000-2100)
BFE>        internal readonly byte[] _months =       new byte[12]; // месяц (1-12)
BFE>        internal readonly byte[] _days =         new byte[32]; // число месяца (1-31 или 32)
BFE>        internal readonly byte[] _weekDays =     new byte[7]; // день недели (0-6)
BFE>        internal readonly byte[] _hours =        new byte[24]; // часы (0-23)
BFE>        internal readonly byte[] _minutes =      new byte[60]; // минуты (0-59)
BFE>        internal readonly byte[] _seconds =      new byte[60]; // секунды (0-59)
BFE>        internal readonly byte[] _milliseconds = new byte[1000]; // миллисекунды (0-999)

BFE>        /// <summary>
BFE>        /// Создает пустой экземпляр, который будет соответствовать
BFE>        /// расписанию типа "*.*.* * *:*:*.*" (раз в 1 мс).
BFE>        /// </summary>
BFE>        public Schedule ()
BFE>            : this ("*.*.* * *:*:*.*")
BFE>        {
BFE>        }

BFE>        /// <summary>
BFE>        /// Создает экземпляр из строки с представлением расписания.
BFE>        /// </summary>
BFE>        /// <param name="scheduleString">Строка расписания.
BFE>        /// Формат строки:
BFE>        ///     yyyy.MM.dd w HH:mm:ss.fff
BFE>        ///     yyyy.MM.dd HH:mm:ss.fff
BFE>        ///     HH:mm:ss.fff
BFE>        ///     yyyy.MM.dd w HH:mm:ss
BFE>        ///     yyyy.MM.dd HH:mm:ss
BFE>        ///     HH:mm:ss
BFE>        /// Где yyyy - год (2000-2100)
BFE>        ///     MM - месяц (1-12)
BFE>        ///     dd - число месяца (1-31 или 32). 32 означает последнее число месяца
BFE>        ///     w - день недели (0-6). 0 - воскресенье, 6 - суббота
BFE>        ///     HH - часы (0-23)
BFE>        ///     mm - минуты (0-59)
BFE>        ///     ss - секунды (0-59)
BFE>        ///     fff - миллисекунды (0-999). Если не указаны, то 0
BFE>        /// Каждую часть даты/времени можно задавать в виде списков и диапазонов.
BFE>        /// Например:
BFE>        ///     1,2,3-5,10-20/3
BFE>        ///     означает список 1,2,3,4,5,10,13,16,19
BFE>        /// Дробью задается шаг в списке.
BFE>        /// Звездочка означает любое возможное значение.
BFE>        /// Например (для часов):
BFE>        ///     */4
BFE>        ///     означает 0,4,8,12,16,20
BFE>        /// Вместо списка чисел месяца можно указать 32. Это означает последнее
BFE>        /// число любого месяца.
BFE>        /// Пример:
BFE>        ///     *.9.*/2 1-5 10:00:00.000
BFE>        ///     означает 10:00 во все дни с пн. по пт. по нечетным числам в сентябре
BFE>        ///     *:00:00
BFE>        ///     означает начало любого часа
BFE>        ///     *.*.01 01:30:00
BFE>        ///     означает 01:30 по первым числам каждого месяца
BFE>        /// </param>
BFE>        public Schedule (string scheduleString)
BFE>        {
BFE>            // конструктор большой по объёму исходника, но выполняет лишь простейшие действия и не выделяет память
BFE>            if (scheduleString == null)
BFE>            {
BFE>                throw new ArgumentNullException (nameof (scheduleString));
BFE>            }

BFE>            var dotPosition1 = scheduleString.IndexOf ('.');
BFE>            var dotPosition2 = (dotPosition1 < 0) ?
BFE>                -1 :
BFE>                scheduleString.IndexOf ('.', dotPosition1 + 1);
BFE>            var dotPosition3 = (dotPosition2 < 0) ?
BFE>                -1 :
BFE>                scheduleString.IndexOf ('.', dotPosition2 + 1);
BFE>            var colonPosition1 = scheduleString.IndexOf (':');
BFE>            var colonPosition2 = (colonPosition1 < 0) ?
BFE>                -1 :
BFE>                scheduleString.IndexOf (':', colonPosition1 + 1);
BFE>            if (colonPosition2 < 0)
BFE>            {
BFE>                // два двоеточия есть во всех форматах
BFE>                throw new FormatException ();
BFE>            }
BFE>            var spacePosition1 = scheduleString.IndexOf (' ');
BFE>            var spacePosition2 = (spacePosition1 < 0) ?
BFE>                -1 :
BFE>                scheduleString.IndexOf (' ', spacePosition1 + 1);

BFE>            ReadOnlySpan<char> yearPart;
BFE>            ReadOnlySpan<char> monthPart;
BFE>            ReadOnlySpan<char> dayPart;
BFE>            ReadOnlySpan<char> weekDayPart;
BFE>            ReadOnlySpan<char> hourPart;
BFE>            ReadOnlySpan<char> minutePart;
BFE>            ReadOnlySpan<char> secondPart;
BFE>            ReadOnlySpan<char> millisecondPart;
BFE>            if (
BFE>                (dotPosition1 >= 0) &&
BFE>                (dotPosition2 >= 0) &&
BFE>                (dotPosition3 >= 0) &&
BFE>                (colonPosition1 > dotPosition2) &&
BFE>                (dotPosition3 > colonPosition2))
BFE>            {
BFE>                // yyyy.MM.dd w HH:mm:ss.fff  или  yyyy.MM.dd HH:mm:ss.fff
BFE>                yearPart = scheduleString.AsSpan (0, dotPosition1);
BFE>                monthPart = scheduleString.AsSpan (dotPosition1 + 1, dotPosition2 - dotPosition1 - 1);
BFE>                dayPart = scheduleString.AsSpan (dotPosition2 + 1, spacePosition1 - dotPosition2 - 1);
BFE>                weekDayPart = (spacePosition2 < 0) ?
BFE>                    _placeholder :
BFE>                    scheduleString.AsSpan (spacePosition1 + 1, spacePosition2 - spacePosition1 - 1);
BFE>                hourPart = (spacePosition2 < 0) ?
BFE>                    scheduleString.AsSpan (spacePosition1 + 1, colonPosition1 - spacePosition1 - 1) :
BFE>                    scheduleString.AsSpan (spacePosition2 + 1, colonPosition1 - spacePosition2 - 1);
BFE>                minutePart = scheduleString.AsSpan (colonPosition1 + 1, colonPosition2 - colonPosition1 - 1);
BFE>                secondPart = scheduleString.AsSpan (colonPosition2 + 1, dotPosition3 - colonPosition2 - 1);
BFE>                millisecondPart = scheduleString.AsSpan (dotPosition3 + 1);
BFE>            }
BFE>            else
BFE>            {
BFE>                if (
BFE>                    (dotPosition1 >= 0) &&
BFE>                    (dotPosition2 >= 0) &&
BFE>                    (dotPosition3 < 0) &&
BFE>                    (colonPosition1 > dotPosition2))
BFE>                {
BFE>                    // yyyy.MM.dd w HH:mm:ss  или  yyyy.MM.dd HH:mm:ss
BFE>                    yearPart = scheduleString.AsSpan (0, dotPosition1);
BFE>                    monthPart = scheduleString.AsSpan (dotPosition1 + 1, dotPosition2 - dotPosition1 - 1);
BFE>                    dayPart = scheduleString.AsSpan (dotPosition2 + 1, spacePosition1 - dotPosition2 - 1);
BFE>                    weekDayPart = (spacePosition2 < 0) ?
BFE>                        _placeholder :
BFE>                        scheduleString.AsSpan (spacePosition1 + 1, spacePosition2 - spacePosition1 - 1);
BFE>                    hourPart = (spacePosition2 < 0) ?
BFE>                        scheduleString.AsSpan (spacePosition1 + 1, colonPosition1 - spacePosition1 - 1) :
BFE>                        scheduleString.AsSpan (spacePosition2 + 1, colonPosition1 - spacePosition2 - 1);
BFE>                    minutePart = scheduleString.AsSpan (colonPosition1 + 1, colonPosition2 - colonPosition1 - 1);
BFE>                    secondPart = scheduleString.AsSpan (colonPosition2 + 1);
BFE>                    millisecondPart = _defaultMilliseconds;
BFE>                }
BFE>                else
BFE>                {
BFE>                    if (
BFE>                        (dotPosition1 >= 0) &&
BFE>                        (dotPosition2 < 0) &&
BFE>                        (colonPosition2 < dotPosition1))
BFE>                    {
BFE>                        // HH:mm:ss.fff
BFE>                        yearPart = _placeholder;
BFE>                        monthPart = _placeholder;
BFE>                        dayPart = _placeholder;
BFE>                        weekDayPart = _placeholder;
BFE>                        hourPart = scheduleString.AsSpan (0, colonPosition1);
BFE>                        minutePart = scheduleString.AsSpan (colonPosition1 + 1, colonPosition2 - colonPosition1 - 1);
BFE>                        secondPart = scheduleString.AsSpan (colonPosition2 + 1, dotPosition1 - colonPosition2 - 1);
BFE>                        millisecondPart = scheduleString.AsSpan (dotPosition1 + 1);
BFE>                    }
BFE>                    else
BFE>                    {
BFE>                        if (dotPosition1 < 0)
BFE>                        {
BFE>                            // HH:mm:ss
BFE>                            yearPart = _placeholder;
BFE>                            monthPart = _placeholder;
BFE>                            dayPart = _placeholder;
BFE>                            weekDayPart = _placeholder;
BFE>                            hourPart = scheduleString.AsSpan (0, colonPosition1);
BFE>                            minutePart = scheduleString.AsSpan (colonPosition1 + 1, colonPosition2 - colonPosition1 - 1);
BFE>                            secondPart = scheduleString.AsSpan (colonPosition2 + 1);
BFE>                            millisecondPart = _defaultMilliseconds;
BFE>                        }
BFE>                        else
BFE>                        {
BFE>                            throw new FormatException ("Unrecognized schedule.");
BFE>                        }
BFE>                    }
BFE>                }
BFE>            }

BFE>            ParsePart (yearPart,        _years,        2000);
BFE>            ParsePart (monthPart,       _months,       1);
BFE>            ParsePart (dayPart,         _days,         1);
BFE>            ParsePart (weekDayPart,     _weekDays,     0);
BFE>            ParsePart (hourPart,        _hours,        0);
BFE>            ParsePart (minutePart,      _minutes,      0);
BFE>            ParsePart (secondPart,      _seconds,      0);
BFE>            ParsePart (millisecondPart, _milliseconds, 0);
BFE>        }

BFE>        /// <summary>
BFE>        /// Возвращает следующий ближайший к заданному времени момент в расписании или
BFE>        /// само заданное время, если оно есть в расписании.
BFE>        /// </summary>
BFE>        /// <param name="t1">Заданное время</param>
BFE>        /// <returns>Ближайший момент времени в расписании</returns>
BFE>        public DateTime NearestEvent(DateTime t1)
BFE>        {
BFE>            // цикл проверки каждый раз после корректировки времени, макс. кол-во итераций: 100 + 11 + 31 + 23 + 59 + 59 = 283
BFE>            while (true)
BFE>            {
BFE>                var yearOffset = t1.Year - 2000;
BFE>                if ((yearOffset < 0) || (yearOffset >= _years.Length))
BFE>                {
BFE>                    throw new InvalidOperationException ("Year out of range");
BFE>                }

BFE>                if (_years[yearOffset] > 0)
BFE>                {
BFE>                    if (_months[t1.Month - 1] > 0)
BFE>                    {
BFE>                        var isLastDayInMonth = t1.Day == DateTime.DaysInMonth (t1.Year, t1.Month);
BFE>                        // 32-й день означает последнее число месяца
BFE>                        if (((_days[t1.Day - 1] > 0) || (isLastDayInMonth && (_days[31] > 0))) && (_weekDays[(int)t1.DayOfWeek] > 0))
BFE>                        {
BFE>                            if (_hours[t1.Hour] > 0)
BFE>                            {
BFE>                                if (_minutes[t1.Minute] > 0)
BFE>                                {
BFE>                                    if (_seconds[t1.Second] > 0)
BFE>                                    {
BFE>                                        var millisecond = t1.Millisecond;
BFE>                                        do
BFE>                                        {
BFE>                                            if (_milliseconds[millisecond] > 0)
BFE>                                            {
BFE>                                                return new DateTime (t1.Year, t1.Month, t1.Day, t1.Hour, t1.Minute, t1.Second, millisecond);
BFE>                                            }

BFE>                                            millisecond++;
BFE>                                        } while (millisecond < _milliseconds.Length);
BFE>                                    }
BFE>                                    t1 = new DateTime (t1.Year, t1.Month, t1.Day, t1.Hour, t1.Minute, t1.Second).AddSeconds (1);
BFE>                                }
BFE>                                else
BFE>                                {
BFE>                                    t1 = new DateTime (t1.Year, t1.Month, t1.Day, t1.Hour, t1.Minute, 0).AddMinutes (1);
BFE>                                }
BFE>                            }
BFE>                            else
BFE>                            {
BFE>                                t1 = new DateTime (t1.Year, t1.Month, t1.Day, t1.Hour, 0, 0).AddHours (1);
BFE>                            }
BFE>                        }
BFE>                        else
BFE>                        {
BFE>                            t1 = new DateTime (t1.Year, t1.Month, t1.Day).AddDays (1);
BFE>                        }
BFE>                    }
BFE>                    else
BFE>                    {
BFE>                        t1 = new DateTime (t1.Year, t1.Month, 1).AddMonths (1);
BFE>                    }
BFE>                }
BFE>                else
BFE>                {
BFE>                    t1 = new DateTime (t1.Year, 1, 1).AddYears (1);
BFE>                }
BFE>            }
BFE>        }

BFE>        /// <summary>
BFE>        /// Возвращает предыдущий ближайший к заданному времени момент в расписании или
BFE>        /// само заданное время, если оно есть в расписании.
BFE>        /// </summary>
BFE>        /// <param name="t1">Заданное время</param>
BFE>        /// <returns>Ближайший момент времени в расписании</returns>
BFE>        public DateTime NearestPrevEvent(DateTime t1)
BFE>        {
BFE>            // цикл проверки каждый раз после корректировки времени, макс. кол-во итераций: 100 + 11 + 31 + 23 + 59 + 59 = 283
BFE>            while (true)
BFE>            {
BFE>                var yearOffset = t1.Year - 2000;
BFE>                if ((yearOffset < 0) || (yearOffset >= _years.Length))
BFE>                {
BFE>                    throw new InvalidOperationException ("Year out of range");
BFE>                }

BFE>                if (_years[yearOffset] > 0)
BFE>                {
BFE>                    if (_months[t1.Month - 1] > 0)
BFE>                    {
BFE>                        var isLastDayInMonth = t1.Day == DateTime.DaysInMonth (t1.Year, t1.Month);
BFE>                        // 32-й день означает последнее число месяца
BFE>                        if (((_days[t1.Day - 1] > 0) || (isLastDayInMonth && (_days[31] > 0))) && (_weekDays[(int)t1.DayOfWeek] > 0))
BFE>                        {
BFE>                            if (_hours[t1.Hour] > 0)
BFE>                            {
BFE>                                if (_minutes[t1.Minute] > 0)
BFE>                                {
BFE>                                    if (_seconds[t1.Second] > 0)
BFE>                                    {
BFE>                                        var millisecond = t1.Millisecond;
BFE>                                        do
BFE>                                        {
BFE>                                            if (_milliseconds[millisecond] > 0)
BFE>                                            {
BFE>                                                return new DateTime (t1.Year, t1.Month, t1.Day, t1.Hour, t1.Minute, t1.Second, millisecond);
BFE>                                            }

BFE>                                            millisecond--;
BFE>                                        } while (millisecond >= 0);
BFE>                                    }
BFE>                                    t1 = new DateTime (t1.Year, t1.Month, t1.Day, t1.Hour, t1.Minute, t1.Second).AddMilliseconds (-1);
BFE>                                }
BFE>                                else
BFE>                                {
BFE>                                    t1 = new DateTime (t1.Year, t1.Month, t1.Day, t1.Hour, t1.Minute, 0).AddMilliseconds (-1);
BFE>                                }
BFE>                            }
BFE>                            else
BFE>                            {
BFE>                                t1 = new DateTime (t1.Year, t1.Month, t1.Day, t1.Hour, 0, 0).AddMilliseconds (-1);
BFE>                            }
BFE>                        }
BFE>                        else
BFE>                        {
BFE>                            t1 = new DateTime (t1.Year, t1.Month, t1.Day).AddMilliseconds (-1);
BFE>                        }
BFE>                    }
BFE>                    else
BFE>                    {
BFE>                        t1 = new DateTime (t1.Year, t1.Month, 1).AddMilliseconds (-1);
BFE>                    }
BFE>                }
BFE>                else
BFE>                {
BFE>                    t1 = new DateTime (t1.Year, 1, 1).AddMilliseconds (-1);
BFE>                }
BFE>            }
BFE>        }

BFE>        /// <summary>
BFE>        /// Возвращает следующий момент времени в расписании.
BFE>        /// </summary>
BFE>        /// <param name="t1">Время, от которого нужно отступить</param>
BFE>        /// <returns>Следующий момент времени в расписании</returns>
BFE>        public DateTime NextEvent(DateTime t1)
BFE>        {
BFE>            return NearestEvent (t1.AddMilliseconds (1));
BFE>        }

BFE>        /// <summary>
BFE>        /// Возвращает предыдущий момент времени в расписании.
BFE>        /// </summary>
BFE>        /// <param name="t1">Время, от которого нужно отступить</param>
BFE>        /// <returns>Предыдущий момент времени в расписании</returns>
BFE>        public DateTime PrevEvent(DateTime t1)
BFE>        {
BFE>            return NearestPrevEvent (t1.AddMilliseconds (-1));
BFE>        }

BFE>        /// <summary>
BFE>        /// Заполняет указанный массив ненулевыми значениями для тех индексов, которые указаны в partStr.
BFE>        /// </summary>
BFE>        /// <param name="partStr">Текстовый список диапазонов.</param>
BFE>        /// <param name="allowedValues">Массив, в котором будут отмечены ненулевым значением указанные в partStr числа.</param>
BFE>        /// <param name="offset">Смещение, которое будет вычитаться для всех чисел, указанных в partStr.</param>
BFE>        private static void ParsePart (ReadOnlySpan<char> partStr, byte[] allowedValues, int offset)
BFE>        {
BFE>            // Каждую часть даты/времени можно задавать в виде списков и диапазонов.
BFE>            // Например:
BFE>            //     1,2,3-5,10-20/3
BFE>            //     означает список 1,2,3,4,5,10,13,16,19
BFE>            // Дробью задается шаг в списке.
BFE>            // Звездочка означает любое возможное значение.

BFE>            if (partStr.Length < 1)
BFE>            {
BFE>                throw new FormatException ("Invalid part");
BFE>            }

BFE>            var idx = 0;
BFE>            while (idx < partStr.Length)
BFE>            {
BFE>                int number1;
BFE>                int number2;
BFE>                if (partStr[idx] == '*')
BFE>                {
BFE>                    idx++;
BFE>                    number1 = 0;
BFE>                    number2 = allowedValues.Length - 1;
BFE>                }
BFE>                else
BFE>                {
BFE>                    number1 = ParseNumber (partStr, ref idx) - offset;
BFE>                    if ((number1 < 0) || (number1 >= allowedValues.Length))
BFE>                    {
BFE>                        throw new FormatException ("Number out of range.");
BFE>                    }

BFE>                    number2 = number1;
BFE>                    if ((idx < partStr.Length) && (partStr[idx] == '-'))
BFE>                    {
BFE>                        idx++;
BFE>                        number2 = ParseNumber (partStr, ref idx) - offset;
BFE>                        if ((number2 < 0) || (number2 >= allowedValues.Length))
BFE>                        {
BFE>                            throw new FormatException ("Number out of range.");
BFE>                        }
BFE>                    }
BFE>                }

BFE>                var period = 1;
BFE>                if (idx < partStr.Length)
BFE>                {
BFE>                    switch (partStr[idx])
BFE>                    {
BFE>                        case '/':
BFE>                            idx++;
BFE>                            period = ParseNumber (partStr, ref idx);
BFE>                            break;
BFE>                        case ',':
BFE>                            idx++;
BFE>                            break;
BFE>                        default:
BFE>                            throw new FormatException ("Invalid character.");
BFE>                    }
BFE>                }

BFE>                for (var i = number1; i <= number2; i += period)
BFE>                {
BFE>                    allowedValues[i] = 1;
BFE>                }
BFE>            }
BFE>        }

BFE>        // возвращает число, полученное из текстового представленая в partStr начиная с индекса в idx
BFE>        private static int ParseNumber (ReadOnlySpan<char> partStr, ref int idx)
BFE>        {
BFE>            var number = 0;
BFE>            while ((idx < partStr.Length) && (partStr[idx] >= '0') && (partStr[idx] <= '9'))
BFE>            {
BFE>                number = 10 * number + partStr[idx] - '0';
BFE>                idx++;
BFE>            }

BFE>            return number;
BFE>        }
BFE>    }
BFE>}
BFE>



Какой вывих мозга? Всё же совершенно очевидно:
     // 32-й день означает последнее число месяца


Все возмущаются вложенностью условий... Да этот господин и одно-то условие не может написать толком:

    if (((_days[t1.Day - 1] > 0) || (isLastDayInMonth && (_days[31] > 0))) && (_weekDays[(int)t1.DayOfWeek] > 0))


Приоритет математических операций изучают во втором классе школы. Судя по правописанию, автор закончил только первый.
Re[2]: Просидев на одном предприятии несколько лет...
От: vaa  
Дата: 11.08.21 06:12
Оценка: +3
Здравствуйте, scf, Вы писали:

scf>На хабре выложили интересный разбор решения и предложили "как надо" https://habr.com/ru/post/572052/


Мне одному кажется, что "как надо" не лучше, чем "как получилось" по большому счёту?
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[3]: Просидев на одном предприятии несколько лет...
От: Gradiens  
Дата: 13.08.21 14:48
Оценка: 12 (1) +1
Здравствуйте, vaa, Вы писали:

vaa>Здравствуйте, Gradiens, Вы писали:


G>>Как человек, недавно побывавший как с одной, так и с другой стороны баррикад, недоумеваю, зачем в такой реальности вообще тратить время на тестовые задания?

vaa>

vaa>верхи не могут низы не хотят

vaa>или наоборот.

А причем тут это?

Смотри, я как соискатель просто не хочу тратить время на задание. Потому что за это время смогу пройти 2-3 интервью.
Я как работодатель не хочу тратить время на разбор чьих-то каракуль. Мне и на моем проекте хватает код-ревью. Я лучше дам человеку пример кода на 1 экран и попрошу проревьювить. И за 10-15 мин станет ясно, имеет ли смысл дальнейший диалог.

Так что никто не хочет ))
Просидев на одном предприятии несколько лет...
От: vaa  
Дата: 06.08.21 02:28
Оценка: 1 (1) :)
https://habr.com/ru/post/571342/
Читаю комменты второй день и . Парадоксально на мой взгляд, но никто до сих пор(региться не охота)
не отметил:
1. быть может отказали почуяв крутого кулцхакера(конкурента).
слышал в крупных компаниях есть такое ограничение — слишком умных не брать, чтобы не взломали систему.
2. "Просидев на одном предприятии несколько лет...", таки зачем срываться? похоже на минутную слабость.
3. почему-то все крутые прогеры пока только накидывают критики, но никто не показал образцовое решение.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Отредактировано 06.08.2021 2:30 Разраб . Предыдущая версия .
Re: Просидев на одном предприятии несколько лет...
От: scf  
Дата: 06.08.21 17:27
Оценка: +2
Здравствуйте, vaa, Вы писали:

vaa>https://habr.com/ru/post/571342/

vaa>Читаю комменты второй день и . Парадоксально на мой взгляд, но никто до сих пор(региться не охота)

Ну это, простите, жесть. Код джуна с математическим бэкграундом.
Паттерны в конструкторе можно и нужно парсить регуляркой, очевидно же, что никто не будет в проде создавать 100500 расписаний, а вот NearestEvent будут вызывать много и часто.
Мартин плачет кровавыми слезами — ну что за уровни вложенности, на дворе 21 век и все компиляторы умеют в инлайнинг.
Перезапись аргумента метода в теле — тоже так себе идея.
Ок, мы решили понять задание буквально и сделать "круче всего" (эх, где мой юношеский максимализм). Но где тогда часовой пояс, по которому всё это считается? И где обширный коммент, объясняющий, как это работает и какие есть тонкости?

Я вообще сделал бы коммент а-ля "календарь — штука сложная вычислительно и в принципе, летнее/зимнее время, leap second и изменения в законодательстве, касающегося времени, сложны и, скорее всего, не важны для шедулера, поэтому у нас всё будет в UTC"

P.S. И, конечно, сначала посмотрел бы, как умные люди это уже реализовали
Re: Просидев на одном предприятии несколько лет...
От: AlexMld Россия  
Дата: 09.08.21 19:45
Оценка: :))
Здравствуйте, vaa, Вы писали:

vaa>https://habr.com/ru/post/571342/


Вот это что?

internal readonly byte[] _years =        new byte[101]; // год (2000-2100)
internal readonly byte[] _months =       new byte[12]; // месяц (1-12)
internal readonly byte[] _days =         new byte[32]; // число месяца (1-31 или 32)
internal readonly byte[] _weekDays =     new byte[7]; // день недели (0-6)
internal readonly byte[] _hours =        new byte[24]; // часы (0-23)
internal readonly byte[] _minutes =      new byte[60]; // минуты (0-59)
internal readonly byte[] _seconds =      new byte[60]; // секунды (0-59)
internal readonly byte[] _milliseconds = new byte[1000]; // миллисекунды (0-999)


Зачем, например, под миллисекунды 1000 байт? По байту на каждое возможное значение? 60 байт на секунды, 60 на минуты и т.п. Зачем? Странный какой-то код у него.
Re: Просидев на одном предприятии несколько лет...
От: elmal  
Дата: 11.08.21 07:53
Оценка: +1 :)
Здравствуйте, vaa, Вы писали:

vaa>1. быть может отказали почуяв крутого кулцхакера(конкурента).

vaa>слышал в крупных компаниях есть такое ограничение — слишком умных не брать, чтобы не взломали систему.
Вообще то слишком умных, которые хреначат 10 уровней вложенности в методе и которых потом не коробит от этого действительно лучше не брать. Ибо я на код мельком посмотрел — мне сразу стало хреново! И это у автора было до черта времени и он делал не спеша, страшно представить что он будет делать когда сроки горят. Так что я полностью на стороне отказавших, сразу по коду виден уровень, что человек был единственным программистом, которого по рукам ни черта не били, при этом даже всяких Макконелов он никогда не читал.
Re[4]: Просидев на одном предприятии несколько лет...
От: RonWilson Россия  
Дата: 11.08.21 09:21
Оценка: +1 :)
Здравствуйте, elmal, Вы писали:

E> ...пишу лютую жуть... и я сам там не помер.... я сразу хреначил тем жутким спагетти... я бы от багов в процессе отладки помер....


какая у Вас опасная работа
Re[2]: Просидев на одном предприятии несколько лет...
От: mgu  
Дата: 11.08.21 22:12
Оценка: +1 :)
Здравствуйте, scf, Вы писали:

scf>На хабре выложили интересный разбор решения и предложили "как надо" https://habr.com/ru/post/572052/


Я наверно пропустил, там конкурс на лучшего говнокодера?

  while (true)
  {
    ...

    if (t1.Month != month)
    {
      continue;
    }
  }


Один гордится тем, что не может написать if, а этот не осилил do while.

Подглядев у Quartz как они ищут дни недели пишем аналогично, сначала подбираем год:

public DateTime NearestEvent(DateTime t1)
{
  while (true)
  {
    while (!_innerSchedule.Years.IsPointAllowed(t1.Year))
    {
      t1 = new DateTime(t1.Year, 1, 1).AddYears(1);
    }
    return t1;
  }
}


Говнокодерство заразно!
Re[5]: Просидев на одном предприятии несколько лет...
От: mgu  
Дата: 12.08.21 15:55
Оценка: :))
Здравствуйте, vaa, Вы писали:

vaa>еще бросилось в глаза что год с 2000 начинаться должен. т.е. задание вероятно очень древнее.


У меня уже скопился архив тестовых заданий, я в них только добавляю современного сахара. Жизнь коротка, тесты вечны!
Re: Просидев на одном предприятии несколько лет...
От: Gradiens  
Дата: 12.08.21 21:09
Оценка: +2
Здравствуйте, vaa, Вы писали:

vaa>https://habr.com/ru/post/571342/

vaa>Читаю комменты второй день и . Парадоксально на мой взгляд, но никто до сих пор(региться не охота)
vaa>не отметил:

Я просмотрел мельком комменты и тут и на хабре.

И парадоксально другое: никто не отметил, что сейчас такая дикая нехватка кадров, что только вывесив резюме спец получает несколько приглашений на собес каждый день. А компании не могут закрыть вакансии месяцами, если они только не вывешивают ценник сильно выше рынка.
Как человек, недавно побывавший как с одной, так и с другой стороны баррикад, недоумеваю, зачем в такой реальности вообще тратить время на тестовые задания?
Re: Просидев на одном предприятии несколько лет...
От: Vladek Россия Github
Дата: 16.08.21 13:45
Оценка: +2
Здравствуйте, vaa, Вы писали:

vaa>https://habr.com/ru/post/571342/

vaa>3. почему-то все крутые прогеры пока только накидывают критики, но никто не показал образцовое решение.

Я бы написал однопроходный парсер: разбитие на базовые лексемы, потом на компоненты, потом выявление списков и диапазонов. И это только первая часть задания. Вторая часть про окрашивание графов вроде (работа с расписанием).

Тут поминают регэкспы — но не все умеют их писать, ещё меньше читать, а уж реализовать свой смогут считанные единицы. C ними код точно быстро превратится в write-only — перед каждым изменением в него надо будет въезжать заново.

Задание конечно же совсем не на сутки — думаю, за неделю можно что-то изобразить. Но зачем? Чтобы удостоиться чести быть приглашенным на дальнейший разговор? Разговор до задания в любом случае необходим — может там такая контора и так организована процесс/работа, что тебя это не устраивает любом случае.
Re: Просидев на одном предприятии несколько лет...
От: scf  
Дата: 10.08.21 19:59
Оценка: 3 (1)
Здравствуйте, vaa, Вы писали:

vaa>3. почему-то все крутые прогеры пока только накидывают критики, но никто не показал образцовое решение.


На хабре выложили интересный разбор решения и предложили "как надо" https://habr.com/ru/post/572052/
Re: Просидев на одном предприятии несколько лет...
От: B0FEE664  
Дата: 06.08.21 16:43
Оценка: :)
Здравствуйте, vaa, Вы писали:

vaa>3. почему-то все крутые прогеры пока только накидывают критики, но никто не показал образцовое решение.

Какой самобытный код!
Я очарован этим кодом.
  Опасно! Не для слабых умов. При чтении можно заработать вывих мозга:
using System;

namespace TestApp
{
    /// <summary>
    /// Класс для задания и расчета времени по расписанию.
    /// </summary>
    public class Schedule
    {
        private const string _placeholder = "*"; // Звездочка означает любое возможное значение.
        private const string _defaultMilliseconds = "0"; // fff - миллисекунды (0-999). Если не указаны, то 0

        internal readonly byte[] _years =        new byte[101]; // год (2000-2100)
        internal readonly byte[] _months =       new byte[12]; // месяц (1-12)
        internal readonly byte[] _days =         new byte[32]; // число месяца (1-31 или 32)
        internal readonly byte[] _weekDays =     new byte[7]; // день недели (0-6)
        internal readonly byte[] _hours =        new byte[24]; // часы (0-23)
        internal readonly byte[] _minutes =      new byte[60]; // минуты (0-59)
        internal readonly byte[] _seconds =      new byte[60]; // секунды (0-59)
        internal readonly byte[] _milliseconds = new byte[1000]; // миллисекунды (0-999)

        /// <summary>
        /// Создает пустой экземпляр, который будет соответствовать
        /// расписанию типа "*.*.* * *:*:*.*" (раз в 1 мс).
        /// </summary>
        public Schedule ()
            : this ("*.*.* * *:*:*.*")
        {
        }

        /// <summary>
        /// Создает экземпляр из строки с представлением расписания.
        /// </summary>
        /// <param name="scheduleString">Строка расписания.
        /// Формат строки:
        ///     yyyy.MM.dd w HH:mm:ss.fff
        ///     yyyy.MM.dd HH:mm:ss.fff
        ///     HH:mm:ss.fff
        ///     yyyy.MM.dd w HH:mm:ss
        ///     yyyy.MM.dd HH:mm:ss
        ///     HH:mm:ss
        /// Где yyyy - год (2000-2100)
        ///     MM - месяц (1-12)
        ///     dd - число месяца (1-31 или 32). 32 означает последнее число месяца
        ///     w - день недели (0-6). 0 - воскресенье, 6 - суббота
        ///     HH - часы (0-23)
        ///     mm - минуты (0-59)
        ///     ss - секунды (0-59)
        ///     fff - миллисекунды (0-999). Если не указаны, то 0
        /// Каждую часть даты/времени можно задавать в виде списков и диапазонов.
        /// Например:
        ///     1,2,3-5,10-20/3
        ///     означает список 1,2,3,4,5,10,13,16,19
        /// Дробью задается шаг в списке.
        /// Звездочка означает любое возможное значение.
        /// Например (для часов):
        ///     */4
        ///     означает 0,4,8,12,16,20
        /// Вместо списка чисел месяца можно указать 32. Это означает последнее
        /// число любого месяца.
        /// Пример:
        ///     *.9.*/2 1-5 10:00:00.000
        ///     означает 10:00 во все дни с пн. по пт. по нечетным числам в сентябре
        ///     *:00:00
        ///     означает начало любого часа
        ///     *.*.01 01:30:00
        ///     означает 01:30 по первым числам каждого месяца
        /// </param>
        public Schedule (string scheduleString)
        {
            // конструктор большой по объёму исходника, но выполняет лишь простейшие действия и не выделяет память
            if (scheduleString == null)
            {
                throw new ArgumentNullException (nameof (scheduleString));
            }

            var dotPosition1 = scheduleString.IndexOf ('.');
            var dotPosition2 = (dotPosition1 < 0) ?
                -1 :
                scheduleString.IndexOf ('.', dotPosition1 + 1);
            var dotPosition3 = (dotPosition2 < 0) ?
                -1 :
                scheduleString.IndexOf ('.', dotPosition2 + 1);
            var colonPosition1 = scheduleString.IndexOf (':');
            var colonPosition2 = (colonPosition1 < 0) ?
                -1 :
                scheduleString.IndexOf (':', colonPosition1 + 1);
            if (colonPosition2 < 0)
            {
                // два двоеточия есть во всех форматах
                throw new FormatException ();
            }
            var spacePosition1 = scheduleString.IndexOf (' ');
            var spacePosition2 = (spacePosition1 < 0) ?
                -1 :
                scheduleString.IndexOf (' ', spacePosition1 + 1);

            ReadOnlySpan<char> yearPart;
            ReadOnlySpan<char> monthPart;
            ReadOnlySpan<char> dayPart;
            ReadOnlySpan<char> weekDayPart;
            ReadOnlySpan<char> hourPart;
            ReadOnlySpan<char> minutePart;
            ReadOnlySpan<char> secondPart;
            ReadOnlySpan<char> millisecondPart;
            if (
                (dotPosition1 >= 0) &&
                (dotPosition2 >= 0) &&
                (dotPosition3 >= 0) &&
                (colonPosition1 > dotPosition2) &&
                (dotPosition3 > colonPosition2))
            {
                // yyyy.MM.dd w HH:mm:ss.fff  или  yyyy.MM.dd HH:mm:ss.fff
                yearPart = scheduleString.AsSpan (0, dotPosition1);
                monthPart = scheduleString.AsSpan (dotPosition1 + 1, dotPosition2 - dotPosition1 - 1);
                dayPart = scheduleString.AsSpan (dotPosition2 + 1, spacePosition1 - dotPosition2 - 1);
                weekDayPart = (spacePosition2 < 0) ?
                    _placeholder :
                    scheduleString.AsSpan (spacePosition1 + 1, spacePosition2 - spacePosition1 - 1);
                hourPart = (spacePosition2 < 0) ?
                    scheduleString.AsSpan (spacePosition1 + 1, colonPosition1 - spacePosition1 - 1) :
                    scheduleString.AsSpan (spacePosition2 + 1, colonPosition1 - spacePosition2 - 1);
                minutePart = scheduleString.AsSpan (colonPosition1 + 1, colonPosition2 - colonPosition1 - 1);
                secondPart = scheduleString.AsSpan (colonPosition2 + 1, dotPosition3 - colonPosition2 - 1);
                millisecondPart = scheduleString.AsSpan (dotPosition3 + 1);
            }
            else
            {
                if (
                    (dotPosition1 >= 0) &&
                    (dotPosition2 >= 0) &&
                    (dotPosition3 < 0) &&
                    (colonPosition1 > dotPosition2))
                {
                    // yyyy.MM.dd w HH:mm:ss  или  yyyy.MM.dd HH:mm:ss
                    yearPart = scheduleString.AsSpan (0, dotPosition1);
                    monthPart = scheduleString.AsSpan (dotPosition1 + 1, dotPosition2 - dotPosition1 - 1);
                    dayPart = scheduleString.AsSpan (dotPosition2 + 1, spacePosition1 - dotPosition2 - 1);
                    weekDayPart = (spacePosition2 < 0) ?
                        _placeholder :
                        scheduleString.AsSpan (spacePosition1 + 1, spacePosition2 - spacePosition1 - 1);
                    hourPart = (spacePosition2 < 0) ?
                        scheduleString.AsSpan (spacePosition1 + 1, colonPosition1 - spacePosition1 - 1) :
                        scheduleString.AsSpan (spacePosition2 + 1, colonPosition1 - spacePosition2 - 1);
                    minutePart = scheduleString.AsSpan (colonPosition1 + 1, colonPosition2 - colonPosition1 - 1);
                    secondPart = scheduleString.AsSpan (colonPosition2 + 1);
                    millisecondPart = _defaultMilliseconds;
                }
                else
                {
                    if (
                        (dotPosition1 >= 0) &&
                        (dotPosition2 < 0) &&
                        (colonPosition2 < dotPosition1))
                    {
                        // HH:mm:ss.fff
                        yearPart = _placeholder;
                        monthPart = _placeholder;
                        dayPart = _placeholder;
                        weekDayPart = _placeholder;
                        hourPart = scheduleString.AsSpan (0, colonPosition1);
                        minutePart = scheduleString.AsSpan (colonPosition1 + 1, colonPosition2 - colonPosition1 - 1);
                        secondPart = scheduleString.AsSpan (colonPosition2 + 1, dotPosition1 - colonPosition2 - 1);
                        millisecondPart = scheduleString.AsSpan (dotPosition1 + 1);
                    }
                    else
                    {
                        if (dotPosition1 < 0)
                        {
                            // HH:mm:ss
                            yearPart = _placeholder;
                            monthPart = _placeholder;
                            dayPart = _placeholder;
                            weekDayPart = _placeholder;
                            hourPart = scheduleString.AsSpan (0, colonPosition1);
                            minutePart = scheduleString.AsSpan (colonPosition1 + 1, colonPosition2 - colonPosition1 - 1);
                            secondPart = scheduleString.AsSpan (colonPosition2 + 1);
                            millisecondPart = _defaultMilliseconds;
                        }
                        else
                        {
                            throw new FormatException ("Unrecognized schedule.");
                        }
                    }
                }
            }

            ParsePart (yearPart,        _years,        2000);
            ParsePart (monthPart,       _months,       1);
            ParsePart (dayPart,         _days,         1);
            ParsePart (weekDayPart,     _weekDays,     0);
            ParsePart (hourPart,        _hours,        0);
            ParsePart (minutePart,      _minutes,      0);
            ParsePart (secondPart,      _seconds,      0);
            ParsePart (millisecondPart, _milliseconds, 0);
        }

        /// <summary>
        /// Возвращает следующий ближайший к заданному времени момент в расписании или
        /// само заданное время, если оно есть в расписании.
        /// </summary>
        /// <param name="t1">Заданное время</param>
        /// <returns>Ближайший момент времени в расписании</returns>
        public DateTime NearestEvent(DateTime t1)
        {
            // цикл проверки каждый раз после корректировки времени, макс. кол-во итераций: 100 + 11 + 31 + 23 + 59 + 59 = 283
            while (true)
            {
                var yearOffset = t1.Year - 2000;
                if ((yearOffset < 0) || (yearOffset >= _years.Length))
                {
                    throw new InvalidOperationException ("Year out of range");
                }

                if (_years[yearOffset] > 0)
                {
                    if (_months[t1.Month - 1] > 0)
                    {
                        var isLastDayInMonth = t1.Day == DateTime.DaysInMonth (t1.Year, t1.Month);
                        // 32-й день означает последнее число месяца
                        if (((_days[t1.Day - 1] > 0) || (isLastDayInMonth && (_days[31] > 0))) && (_weekDays[(int)t1.DayOfWeek] > 0))
                        {
                            if (_hours[t1.Hour] > 0)
                            {
                                if (_minutes[t1.Minute] > 0)
                                {
                                    if (_seconds[t1.Second] > 0)
                                    {
                                        var millisecond = t1.Millisecond;
                                        do
                                        {
                                            if (_milliseconds[millisecond] > 0)
                                            {
                                                return new DateTime (t1.Year, t1.Month, t1.Day, t1.Hour, t1.Minute, t1.Second, millisecond);
                                            }

                                            millisecond++;
                                        } while (millisecond < _milliseconds.Length);
                                    }
                                    t1 = new DateTime (t1.Year, t1.Month, t1.Day, t1.Hour, t1.Minute, t1.Second).AddSeconds (1);
                                }
                                else
                                {
                                    t1 = new DateTime (t1.Year, t1.Month, t1.Day, t1.Hour, t1.Minute, 0).AddMinutes (1);
                                }
                            }
                            else
                            {
                                t1 = new DateTime (t1.Year, t1.Month, t1.Day, t1.Hour, 0, 0).AddHours (1);
                            }
                        }
                        else
                        {
                            t1 = new DateTime (t1.Year, t1.Month, t1.Day).AddDays (1);
                        }
                    }
                    else
                    {
                        t1 = new DateTime (t1.Year, t1.Month, 1).AddMonths (1);
                    }
                }
                else
                {
                    t1 = new DateTime (t1.Year, 1, 1).AddYears (1);
                }
            }
        }

        /// <summary>
        /// Возвращает предыдущий ближайший к заданному времени момент в расписании или
        /// само заданное время, если оно есть в расписании.
        /// </summary>
        /// <param name="t1">Заданное время</param>
        /// <returns>Ближайший момент времени в расписании</returns>
        public DateTime NearestPrevEvent(DateTime t1)
        {
            // цикл проверки каждый раз после корректировки времени, макс. кол-во итераций: 100 + 11 + 31 + 23 + 59 + 59 = 283
            while (true)
            {
                var yearOffset = t1.Year - 2000;
                if ((yearOffset < 0) || (yearOffset >= _years.Length))
                {
                    throw new InvalidOperationException ("Year out of range");
                }

                if (_years[yearOffset] > 0)
                {
                    if (_months[t1.Month - 1] > 0)
                    {
                        var isLastDayInMonth = t1.Day == DateTime.DaysInMonth (t1.Year, t1.Month);
                        // 32-й день означает последнее число месяца
                        if (((_days[t1.Day - 1] > 0) || (isLastDayInMonth && (_days[31] > 0))) && (_weekDays[(int)t1.DayOfWeek] > 0))
                        {
                            if (_hours[t1.Hour] > 0)
                            {
                                if (_minutes[t1.Minute] > 0)
                                {
                                    if (_seconds[t1.Second] > 0)
                                    {
                                        var millisecond = t1.Millisecond;
                                        do
                                        {
                                            if (_milliseconds[millisecond] > 0)
                                            {
                                                return new DateTime (t1.Year, t1.Month, t1.Day, t1.Hour, t1.Minute, t1.Second, millisecond);
                                            }

                                            millisecond--;
                                        } while (millisecond >= 0);
                                    }
                                    t1 = new DateTime (t1.Year, t1.Month, t1.Day, t1.Hour, t1.Minute, t1.Second).AddMilliseconds (-1);
                                }
                                else
                                {
                                    t1 = new DateTime (t1.Year, t1.Month, t1.Day, t1.Hour, t1.Minute, 0).AddMilliseconds (-1);
                                }
                            }
                            else
                            {
                                t1 = new DateTime (t1.Year, t1.Month, t1.Day, t1.Hour, 0, 0).AddMilliseconds (-1);
                            }
                        }
                        else
                        {
                            t1 = new DateTime (t1.Year, t1.Month, t1.Day).AddMilliseconds (-1);
                        }
                    }
                    else
                    {
                        t1 = new DateTime (t1.Year, t1.Month, 1).AddMilliseconds (-1);
                    }
                }
                else
                {
                    t1 = new DateTime (t1.Year, 1, 1).AddMilliseconds (-1);
                }
            }
        }

        /// <summary>
        /// Возвращает следующий момент времени в расписании.
        /// </summary>
        /// <param name="t1">Время, от которого нужно отступить</param>
        /// <returns>Следующий момент времени в расписании</returns>
        public DateTime NextEvent(DateTime t1)
        {
            return NearestEvent (t1.AddMilliseconds (1));
        }

        /// <summary>
        /// Возвращает предыдущий момент времени в расписании.
        /// </summary>
        /// <param name="t1">Время, от которого нужно отступить</param>
        /// <returns>Предыдущий момент времени в расписании</returns>
        public DateTime PrevEvent(DateTime t1)
        {
            return NearestPrevEvent (t1.AddMilliseconds (-1));
        }

        /// <summary>
        /// Заполняет указанный массив ненулевыми значениями для тех индексов, которые указаны в partStr.
        /// </summary>
        /// <param name="partStr">Текстовый список диапазонов.</param>
        /// <param name="allowedValues">Массив, в котором будут отмечены ненулевым значением указанные в partStr числа.</param>
        /// <param name="offset">Смещение, которое будет вычитаться для всех чисел, указанных в partStr.</param>
        private static void ParsePart (ReadOnlySpan<char> partStr, byte[] allowedValues, int offset)
        {
            // Каждую часть даты/времени можно задавать в виде списков и диапазонов.
            // Например:
            //     1,2,3-5,10-20/3
            //     означает список 1,2,3,4,5,10,13,16,19
            // Дробью задается шаг в списке.
            // Звездочка означает любое возможное значение.

            if (partStr.Length < 1)
            {
                throw new FormatException ("Invalid part");
            }

            var idx = 0;
            while (idx < partStr.Length)
            {
                int number1;
                int number2;
                if (partStr[idx] == '*')
                {
                    idx++;
                    number1 = 0;
                    number2 = allowedValues.Length - 1;
                }
                else
                {
                    number1 = ParseNumber (partStr, ref idx) - offset;
                    if ((number1 < 0) || (number1 >= allowedValues.Length))
                    {
                        throw new FormatException ("Number out of range.");
                    }

                    number2 = number1;
                    if ((idx < partStr.Length) && (partStr[idx] == '-'))
                    {
                        idx++;
                        number2 = ParseNumber (partStr, ref idx) - offset;
                        if ((number2 < 0) || (number2 >= allowedValues.Length))
                        {
                            throw new FormatException ("Number out of range.");
                        }
                    }
                }

                var period = 1;
                if (idx < partStr.Length)
                {
                    switch (partStr[idx])
                    {
                        case '/':
                            idx++;
                            period = ParseNumber (partStr, ref idx);
                            break;
                        case ',':
                            idx++;
                            break;
                        default:
                            throw new FormatException ("Invalid character.");
                    }
                }

                for (var i = number1; i <= number2; i += period)
                {
                    allowedValues[i] = 1;
                }
            }
        }

        // возвращает число, полученное из текстового представленая в partStr начиная с индекса в idx
        private static int ParseNumber (ReadOnlySpan<char> partStr, ref int idx)
        {
            var number = 0;
            while ((idx < partStr.Length) && (partStr[idx] >= '0') && (partStr[idx] <= '9'))
            {
                number = 10 * number + partStr[idx] - '0';
                idx++;
            }

            return number;
        }
    }
}
И каждый день — без права на ошибку...
Re[3]: Просидев на одном предприятии несколько лет...
От: Sharov Россия  
Дата: 08.08.21 00:26
Оценка: :)
Здравствуйте, hardcase, Вы писали:

H>ИЧСХ, автор хабрапоста вполне годный код написал.


Не, у него там дикая вложенность на ровном месте. Там читались абстракции для всяких последовательностей +
переложить большую часть проблем с учетом всяческих високосных годов на DataTime. Видно, что человек из R&D.
Кодом людям нужно помогать!
Re: Просидев на одном предприятии несколько лет...
От: rosencrantz США  
Дата: 09.08.21 17:21
Оценка: +1
Здравствуйте, vaa, Вы писали:

vaa>https://habr.com/ru/post/571342/

vaa>Читаю комменты второй день и . Парадоксально на мой взгляд, но никто до сих пор(региться не охота)
vaa>не отметил:
vaa>1. быть может отказали почуяв крутого кулцхакера(конкурента).
vaa>слышал в крупных компаниях есть такое ограничение — слишком умных не брать, чтобы не взломали систему.
vaa>2. "Просидев на одном предприятии несколько лет...", таки зачем срываться? похоже на минутную слабость.
vaa>3. почему-то все крутые прогеры пока только накидывают критики, но никто не показал образцовое решение.

Мне код не нравится — выглядит как "авторский".

1. Для чтения выражений нужно какой-то внятный парсер с внятной грамматикой, или хотя бы регулярные выражения. Чтобы грамматика была не в комментах, а в чём-то более-менее компьютерном. Чтобы можно было красиво ругаться "что qwerty не выглядит как число от 1 до 12".

2. Решение никак не порезано на отдельные логические куски — программу невозможно читать по частям, только как монолит. Я бы попытался дизайнить в сторону "композиции триггеров". Парсим -> дерево разбора -> составной триггер.
Re[3]: Просидев на одном предприятии несколько лет...
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 09.08.21 21:49
Оценка: +1
Здравствуйте, bnk, Вы писали:

bnk>Структура данных для вычисления пересечения интервалов...

Да не, код реально говно. Можно было разить, на сущности, ввести абстракции.
bnk>А что не так, ты бы по-другому сделал? Вроде бы все верно, или нет?
Я не совсем понял задание, но вроде бы хранить всё это можно в банальном красно-чёрном дереве в UTC, тогда слева у тебя всё, что раньше, а справа, всё что позже.
bnk>Альтернатива — задавать интервалами, но это неэффективно.
Зависит от степени извращённости.
Sic luceat lux!
Re[3]: Просидев на одном предприятии несколько лет...
От: vfedosov  
Дата: 10.08.21 18:25
Оценка: +1
mgu>Приоритет математических операций изучают во втором классе школы. Судя по правописанию, автор закончил только первый.

Некоторые конторы заставляют ставить скобки вообще везде, где есть 2 операции и насрать им на приоритет. В Германии, к примеру, в атомобильной промышленности это просто индустриальный стандарт . Конечно, нечитабельно, но выхода нет — пишешь такое гавно.
Отредактировано 10.08.2021 18:26 vfedosov . Предыдущая версия .
Re[4]: Просидев на одном предприятии несколько лет...
От: Тёмчик Австралия жж
Дата: 11.08.21 02:23
Оценка: -1
Здравствуйте, Doom100500, Вы писали:

D>А ставить скобки для удобочтаемости — это нормально.


Я заметил корелляцию кстати (из жизненных наблюдений за коллегами), способности программиста знать приоритет операций, и адекватностью его дизайнов (наркоманы все как один хотят скобки для удобочитаемости).
Re[4]: Просидев на одном предприятии несколько лет...
От: vaa  
Дата: 11.08.21 12:00
Оценка: :)
Здравствуйте, elmal, Вы писали:

E>Во первых там не все 5 дней на фултайме делали.


По кол-ву коммитов не скажешь.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[7]: Просидев на одном предприятии несколько лет...
От: Doom100500 Израиль  
Дата: 12.08.21 05:14
Оценка: -1
Здравствуйте, mgu, Вы писали:

mgu>В конце предложения подразумевалась точка или двоеточие?


mgu>Пропущены 2 запятые. Читаемость!


Т.е. когда сказать нечего, то вполне приемлемо попридираться к запятым и точкам.

mgu>Речь щла о базовом классе "математические операции".


Вот это поворот! (В конце восклицательный знак )

Раз уж здесь принято переводить стрелки, то ловите, уважаемый:

mgu>Я даже техзадания не могу прочитать сходу.


mgu>Автоформатирование появилось не так давно.


Спад умственных способностей и жизнь в прошлом вполне себе являются признаками ранней деменции. Пора начинать беспокоиться.
Спасибо за внимание
Отредактировано 12.08.2021 5:16 Doom100500 . Предыдущая версия .
Re[2]: Просидев на одном предприятии несколько лет...
От: vaa  
Дата: 13.08.21 01:40
Оценка: :)
Здравствуйте, Gradiens, Вы писали:

G>Как человек, недавно побывавший как с одной, так и с другой стороны баррикад, недоумеваю, зачем в такой реальности вообще тратить время на тестовые задания?

верхи не могут низы не хотят

или наоборот.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[2]: Просидев на одном предприятии несколько лет...
От: vaa  
Дата: 06.08.21 09:17
Оценка:
Здравствуйте, CEMb, Вы писали:
CEM>Человек так устроен, что хочет попробовать все альтернативы.
да, уж. как говорила одна знакомая бухгалтер: под лежачий камень вода не течёт.
Тогда я и соскочил с места 10-летней насидки.
Факторов на то повлиявших было много.
Но главное найти свое место в обществе.
Сейчас понимаю любое действие по большому счету бессмысленно. Особенно в обществе потребления.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[2]: Просидев на одном предприятии несколько лет...
От: hardcase Пират http://nemerle.org
Дата: 06.08.21 11:02
Оценка:
Здравствуйте, кубик, Вы писали:

К>Надо идти где отвечают вежливо: "Спасибо за Ваше потраченое время и желание работать в нашей фирме! В настоящее время нам бы хотелось найти человека с бОльшим опытом в данной технологии. Благодарим Вас еще раз и Желаем успехов в вашем профессиональном пути!"


ИЧСХ, автор хабрапоста вполне годный код написал.
/* иЗвиНите зА неРовнЫй поЧерК */
Re[2]: Просидев на одном предприятии несколько лет...
От: Блудов Павел Россия  
Дата: 07.08.21 13:37
Оценка:
Здравствуйте, scf, Вы писали:

scf>P.S. И, конечно, сначала посмотрел бы, как умные люди это уже реализовали


Не-не-не, не нужно смотреть. Там точно такая же простыня, но с регулярками.
Re[2]: Просидев на одном предприятии несколько лет...
От: B0FEE664  
Дата: 07.08.21 14:43
Оценка:
Здравствуйте, Mr.Delphist, Вы писали:

MD>1) Всё врукопашку. Человек вроде не новичок, и даже знает про RegExp, ...

MD>Чем это плохо: случись изменение в формате строки -> старый код в утиль, целиком. Со всеми юнит-тестами и бенчмарками.

Если использовать RegExp, то будет такая же ситуация.

MD>2) Длинные методы, многоуровневые if. По сути, продолжение предыдущего пункта. Читая такой код, понимаешь, что имеешь дело с эдаким C#-ассемблером, дампом мыслленного решения, существующего в голове автора.

Ой, да ладно! Там все if'ы однотипные и читаются влёт.

MD>Чем это плохо: приходится "дизассемблирвоать" эту простыню, чтобы понять, какую проблему решает код, почему в этот if зайти надо, а в следующий — нет. Потому что настоящий "исходник" — так и остаётся в голове автора. Телепатию пока не завезли, увы. Ну и как говорилось выше — цена изменений.


В отличии от парсинга эту часть легко изменить. Однако, следует заменить, что максимальное количество итераций подсчитано не верно: там произведение должно быть, а не сумма.

MD>3) Постановка задачи и "что такое эффективаность для заказчика". Вместо уточнения "вам пуговицы или халат с поясом, сделать из рогожи или из дубовой доски" принимается одностороннее решение "пуговицы будут перламутровыми, так эффективней". В общем, классика мема "что хотел заказчик".


Не согласен. В задании ясно сказано: "класс должен быть эффективным и не использовать много памяти и ресурсов даже тогда, когда в расписании задано много значений. Например очень много значений с шагом в одну миллисекунду." Я понимаю это как требование оптимизацию по памяти, а не по скорости => надо было хранить саму строку расписания и парсить её при каждом запросе.

MD>Выводы:

MD>1) Надо уметь не только язык (это обычно самое простое), но и инфраструктуру прикладных библиотек вокруг него.

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

MD>2) Работа в команде — отдельный вид деятельности, и он необходим хотя бы как этап проф-развития, каким бы гением ты ни был.

А если стиль работы в команде не известен?

MD>3) If at first you don't succeed, try, try again.

Не, тут следует заметить, что "0 — воскресенье, 6 — суббота" — это значит, что задание переводное. Возможно имело смысл поискать (на английском) готовое решение, а не страдать изобретением велосипеда.
И каждый день — без права на ошибку...
Re[2]: Просидев на одном предприятии несколько лет...
От: viellsky  
Дата: 07.08.21 16:56
Оценка:
Здравствуйте, Mr.Delphist, Вы писали:

MD>Таки глянул код — статья получилась резонансная, сыпется из разных мест ленты, пришлось читать. Ну и что могу сказать: я бы тоже не взял. Ровно по той же причине, почему не взял бы себя-раннего с точки зрения себя-сегодняшнего.

Взял/не взял — это одно. А вот почему код охарактеризовали "задание Вы выполнили действительно отвратительно, халтурно" — совсем другое.

MD>1) Всё врукопашку. Человек вроде не новичок, и даже знает про RegExp, но в итоге вся работа по парсингу входной строки — через простыню IndexOf. Не то что токенайзер или Linq, даже обычный Split отсутствует.

MD>Чем это плохо: случись изменение в формате строки -> старый код в утиль, целиком. Со всеми юнит-тестами и бенчмарками.
Юнит-тесту как-то все равно — вручную ты парсишь или вызовом регэкспа. Да и почему старый код в утиль, тоже не понятно — объем изменений может отличаться, да, но опять же — про расход памяти/ресурсов в требованиях написано, а вот про повышенную стойкость к изменению формата — нет. Спорная претензия, в общем.

MD>2) Длинные методы, многоуровневые if. По сути, продолжение предыдущего пункта. Читая такой код, понимаешь, что имеешь дело с эдаким C#-ассемблером, дампом мыслленного решения, существующего в голове автора.

MD>Чем это плохо: приходится "дизассемблирвоать" эту простыню, чтобы понять, какую проблему решает код, почему в этот if зайти надо, а в следующий — нет. Потому что настоящий "исходник" — так и остаётся в голове автора. Телепатию пока не завезли, увы. Ну и как говорилось выше — цена изменений.

Жути нагнал — все не так плохо тут. Ничего сверхдлинного или сверхвложного нет. Если и считать это недостатком — то явно не критичным. Про телепатию вывод сделан наспех по формальным признакам.

MD>3) Постановка задачи и "что такое эффективаность для заказчика". Вместо уточнения "вам пуговицы или халат с поясом, сделать из рогожи или из дубовой доски" принимается одностороннее решение "пуговицы будут перламутровыми, так эффективней". В общем, классика мема "что хотел заказчик".

Автор спрашивал:

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

Re[3]: Просидев на одном предприятии несколько лет...
От: Mr.Delphist  
Дата: 09.08.21 09:14
Оценка:
Здравствуйте, viellsky, Вы писали:

V>Взял/не взял — это одно. А вот почему код охарактеризовали "задание Вы выполнили действительно отвратительно, халтурно" — совсем другое.


О, то отдельная песня. Уже не про соискателя, а про HR-процесс. Единственынй плюсик который там можно поставить — что соискателю ОТВЕТИЛИ, вместо молчаливого вышвыривания в корзину.
Re[2]: Просидев на одном предприятии несколько лет...
От: bnk СССР http://unmanagedvisio.com/
Дата: 09.08.21 19:53
Оценка:
Здравствуйте, AlexMld, Вы писали:

AM>Вот это что?


Структура данных для вычисления пересечения интервалов...

AM>Зачем, например, под миллисекунды 1000 байт? По байту на каждое возможное значение? 60 байт на секунды, 60 на минуты и т.п. Зачем? Странный какой-то код у него.


А что не так, ты бы по-другому сделал? Вроде бы все верно, или нет?
Альтернатива — задавать интервалами, но это неэффективно.
Отредактировано 09.08.2021 19:56 bnk . Предыдущая версия .
Re: Просидев на одном предприятии несколько лет...
От: mgu  
Дата: 10.08.21 01:48
Оценка:
Здравствуйте, vaa, Вы писали:

vaa>https://habr.com/ru/post/571342/

vaa>Читаю комменты второй день и .
vaa>3. почему-то все крутые прогеры пока только накидывают критики, но никто не показал образцовое решение.

Крутые прогеры(тм) обсуждают var vs. тип. Сразу видно, что не лохи, у которых пробелы vs. табуляция.
Re[3]: Просидев на одном предприятии несколько лет...
От: AlexMld Россия  
Дата: 10.08.21 07:34
Оценка:
Здравствуйте, bnk, Вы писали:

bnk>А что не так, ты бы по-другому сделал? Вроде бы все верно, или нет?

bnk>Альтернатива — задавать интервалами, но это неэффективно.

Я, видимо, не внимательно условия задачи прочитал. В принципе, да, можно так.
Re[3]: Просидев на одном предприятии несколько лет...
От: B0FEE664  
Дата: 10.08.21 11:34
Оценка:
Здравствуйте, mgu, Вы писали:

mgu>Здравствуйте, B0FEE664, Вы писали:


vaa>>>3. почему-то все крутые прогеры пока только накидывают критики, но никто не показал образцовое решение.

BFE>>Какой самобытный код!
BFE>>Я очарован этим кодом.
BFE>>
  Опасно! Не для слабых умов. При чтении можно заработать вывих мозга:
BFE>>
BFE>>using System;

BFE>>namespace TestApp
BFE>>{
BFE>>    /// <summary>
BFE>>    /// Класс для задания и расчета времени по расписанию.
BFE>>    /// </summary>
BFE>>    public class Schedule
BFE>>    {
BFE>>        private const string _placeholder = "*"; // Звездочка означает любое возможное значение.
BFE>>        private const string _defaultMilliseconds = "0"; // fff - миллисекунды (0-999). Если не указаны, то 0

BFE>>        internal readonly byte[] _years =        new byte[101]; // год (2000-2100)
BFE>>        internal readonly byte[] _months =       new byte[12]; // месяц (1-12)
BFE>>        internal readonly byte[] _days =         new byte[32]; // число месяца (1-31 или 32)
BFE>>        internal readonly byte[] _weekDays =     new byte[7]; // день недели (0-6)
BFE>>        internal readonly byte[] _hours =        new byte[24]; // часы (0-23)
BFE>>        internal readonly byte[] _minutes =      new byte[60]; // минуты (0-59)
BFE>>        internal readonly byte[] _seconds =      new byte[60]; // секунды (0-59)
BFE>>        internal readonly byte[] _milliseconds = new byte[1000]; // миллисекунды (0-999)

BFE>>        /// <summary>
BFE>>        /// Создает пустой экземпляр, который будет соответствовать
BFE>>        /// расписанию типа "*.*.* * *:*:*.*" (раз в 1 мс).
BFE>>        /// </summary>
BFE>>        public Schedule ()
BFE>>            : this ("*.*.* * *:*:*.*")
BFE>>        {
BFE>>        }

BFE>>        /// <summary>
BFE>>        /// Создает экземпляр из строки с представлением расписания.
BFE>>        /// </summary>
BFE>>        /// <param name="scheduleString">Строка расписания.
BFE>>        /// Формат строки:
BFE>>        ///     yyyy.MM.dd w HH:mm:ss.fff
BFE>>        ///     yyyy.MM.dd HH:mm:ss.fff
BFE>>        ///     HH:mm:ss.fff
BFE>>        ///     yyyy.MM.dd w HH:mm:ss
BFE>>        ///     yyyy.MM.dd HH:mm:ss
BFE>>        ///     HH:mm:ss
BFE>>        /// Где yyyy - год (2000-2100)
BFE>>        ///     MM - месяц (1-12)
BFE>>        ///     dd - число месяца (1-31 или 32). 32 означает последнее число месяца
BFE>>        ///     w - день недели (0-6). 0 - воскресенье, 6 - суббота
BFE>>        ///     HH - часы (0-23)
BFE>>        ///     mm - минуты (0-59)
BFE>>        ///     ss - секунды (0-59)
BFE>>        ///     fff - миллисекунды (0-999). Если не указаны, то 0
BFE>>        /// Каждую часть даты/времени можно задавать в виде списков и диапазонов.
BFE>>        /// Например:
BFE>>        ///     1,2,3-5,10-20/3
BFE>>        ///     означает список 1,2,3,4,5,10,13,16,19
BFE>>        /// Дробью задается шаг в списке.
BFE>>        /// Звездочка означает любое возможное значение.
BFE>>        /// Например (для часов):
BFE>>        ///     */4
BFE>>        ///     означает 0,4,8,12,16,20
BFE>>        /// Вместо списка чисел месяца можно указать 32. Это означает последнее
BFE>>        /// число любого месяца.
BFE>>        /// Пример:
BFE>>        ///     *.9.*/2 1-5 10:00:00.000
BFE>>        ///     означает 10:00 во все дни с пн. по пт. по нечетным числам в сентябре
BFE>>        ///     *:00:00
BFE>>        ///     означает начало любого часа
BFE>>        ///     *.*.01 01:30:00
BFE>>        ///     означает 01:30 по первым числам каждого месяца
BFE>>        /// </param>
BFE>>        public Schedule (string scheduleString)
BFE>>        {
BFE>>            // конструктор большой по объёму исходника, но выполняет лишь простейшие действия и не выделяет память
BFE>>            if (scheduleString == null)
BFE>>            {
BFE>>                throw new ArgumentNullException (nameof (scheduleString));
BFE>>            }

BFE>>            var dotPosition1 = scheduleString.IndexOf ('.');
BFE>>            var dotPosition2 = (dotPosition1 < 0) ?
BFE>>                -1 :
BFE>>                scheduleString.IndexOf ('.', dotPosition1 + 1);
BFE>>            var dotPosition3 = (dotPosition2 < 0) ?
BFE>>                -1 :
BFE>>                scheduleString.IndexOf ('.', dotPosition2 + 1);
BFE>>            var colonPosition1 = scheduleString.IndexOf (':');
BFE>>            var colonPosition2 = (colonPosition1 < 0) ?
BFE>>                -1 :
BFE>>                scheduleString.IndexOf (':', colonPosition1 + 1);
BFE>>            if (colonPosition2 < 0)
BFE>>            {
BFE>>                // два двоеточия есть во всех форматах
BFE>>                throw new FormatException ();
BFE>>            }
BFE>>            var spacePosition1 = scheduleString.IndexOf (' ');
BFE>>            var spacePosition2 = (spacePosition1 < 0) ?
BFE>>                -1 :
BFE>>                scheduleString.IndexOf (' ', spacePosition1 + 1);

BFE>>            ReadOnlySpan<char> yearPart;
BFE>>            ReadOnlySpan<char> monthPart;
BFE>>            ReadOnlySpan<char> dayPart;
BFE>>            ReadOnlySpan<char> weekDayPart;
BFE>>            ReadOnlySpan<char> hourPart;
BFE>>            ReadOnlySpan<char> minutePart;
BFE>>            ReadOnlySpan<char> secondPart;
BFE>>            ReadOnlySpan<char> millisecondPart;
BFE>>            if (
BFE>>                (dotPosition1 >= 0) &&
BFE>>                (dotPosition2 >= 0) &&
BFE>>                (dotPosition3 >= 0) &&
BFE>>                (colonPosition1 > dotPosition2) &&
BFE>>                (dotPosition3 > colonPosition2))
BFE>>            {
BFE>>                // yyyy.MM.dd w HH:mm:ss.fff  или  yyyy.MM.dd HH:mm:ss.fff
BFE>>                yearPart = scheduleString.AsSpan (0, dotPosition1);
BFE>>                monthPart = scheduleString.AsSpan (dotPosition1 + 1, dotPosition2 - dotPosition1 - 1);
BFE>>                dayPart = scheduleString.AsSpan (dotPosition2 + 1, spacePosition1 - dotPosition2 - 1);
BFE>>                weekDayPart = (spacePosition2 < 0) ?
BFE>>                    _placeholder :
BFE>>                    scheduleString.AsSpan (spacePosition1 + 1, spacePosition2 - spacePosition1 - 1);
BFE>>                hourPart = (spacePosition2 < 0) ?
BFE>>                    scheduleString.AsSpan (spacePosition1 + 1, colonPosition1 - spacePosition1 - 1) :
BFE>>                    scheduleString.AsSpan (spacePosition2 + 1, colonPosition1 - spacePosition2 - 1);
BFE>>                minutePart = scheduleString.AsSpan (colonPosition1 + 1, colonPosition2 - colonPosition1 - 1);
BFE>>                secondPart = scheduleString.AsSpan (colonPosition2 + 1, dotPosition3 - colonPosition2 - 1);
BFE>>                millisecondPart = scheduleString.AsSpan (dotPosition3 + 1);
BFE>>            }
BFE>>            else
BFE>>            {
BFE>>                if (
BFE>>                    (dotPosition1 >= 0) &&
BFE>>                    (dotPosition2 >= 0) &&
BFE>>                    (dotPosition3 < 0) &&
BFE>>                    (colonPosition1 > dotPosition2))
BFE>>                {
BFE>>                    // yyyy.MM.dd w HH:mm:ss  или  yyyy.MM.dd HH:mm:ss
BFE>>                    yearPart = scheduleString.AsSpan (0, dotPosition1);
BFE>>                    monthPart = scheduleString.AsSpan (dotPosition1 + 1, dotPosition2 - dotPosition1 - 1);
BFE>>                    dayPart = scheduleString.AsSpan (dotPosition2 + 1, spacePosition1 - dotPosition2 - 1);
BFE>>                    weekDayPart = (spacePosition2 < 0) ?
BFE>>                        _placeholder :
BFE>>                        scheduleString.AsSpan (spacePosition1 + 1, spacePosition2 - spacePosition1 - 1);
BFE>>                    hourPart = (spacePosition2 < 0) ?
BFE>>                        scheduleString.AsSpan (spacePosition1 + 1, colonPosition1 - spacePosition1 - 1) :
BFE>>                        scheduleString.AsSpan (spacePosition2 + 1, colonPosition1 - spacePosition2 - 1);
BFE>>                    minutePart = scheduleString.AsSpan (colonPosition1 + 1, colonPosition2 - colonPosition1 - 1);
BFE>>                    secondPart = scheduleString.AsSpan (colonPosition2 + 1);
BFE>>                    millisecondPart = _defaultMilliseconds;
BFE>>                }
BFE>>                else
BFE>>                {
BFE>>                    if (
BFE>>                        (dotPosition1 >= 0) &&
BFE>>                        (dotPosition2 < 0) &&
BFE>>                        (colonPosition2 < dotPosition1))
BFE>>                    {
BFE>>                        // HH:mm:ss.fff
BFE>>                        yearPart = _placeholder;
BFE>>                        monthPart = _placeholder;
BFE>>                        dayPart = _placeholder;
BFE>>                        weekDayPart = _placeholder;
BFE>>                        hourPart = scheduleString.AsSpan (0, colonPosition1);
BFE>>                        minutePart = scheduleString.AsSpan (colonPosition1 + 1, colonPosition2 - colonPosition1 - 1);
BFE>>                        secondPart = scheduleString.AsSpan (colonPosition2 + 1, dotPosition1 - colonPosition2 - 1);
BFE>>                        millisecondPart = scheduleString.AsSpan (dotPosition1 + 1);
BFE>>                    }
BFE>>                    else
BFE>>                    {
BFE>>                        if (dotPosition1 < 0)
BFE>>                        {
BFE>>                            // HH:mm:ss
BFE>>                            yearPart = _placeholder;
BFE>>                            monthPart = _placeholder;
BFE>>                            dayPart = _placeholder;
BFE>>                            weekDayPart = _placeholder;
BFE>>                            hourPart = scheduleString.AsSpan (0, colonPosition1);
BFE>>                            minutePart = scheduleString.AsSpan (colonPosition1 + 1, colonPosition2 - colonPosition1 - 1);
BFE>>                            secondPart = scheduleString.AsSpan (colonPosition2 + 1);
BFE>>                            millisecondPart = _defaultMilliseconds;
BFE>>                        }
BFE>>                        else
BFE>>                        {
BFE>>                            throw new FormatException ("Unrecognized schedule.");
BFE>>                        }
BFE>>                    }
BFE>>                }
BFE>>            }

BFE>>            ParsePart (yearPart,        _years,        2000);
BFE>>            ParsePart (monthPart,       _months,       1);
BFE>>            ParsePart (dayPart,         _days,         1);
BFE>>            ParsePart (weekDayPart,     _weekDays,     0);
BFE>>            ParsePart (hourPart,        _hours,        0);
BFE>>            ParsePart (minutePart,      _minutes,      0);
BFE>>            ParsePart (secondPart,      _seconds,      0);
BFE>>            ParsePart (millisecondPart, _milliseconds, 0);
BFE>>        }

BFE>>        /// <summary>
BFE>>        /// Возвращает следующий ближайший к заданному времени момент в расписании или
BFE>>        /// само заданное время, если оно есть в расписании.
BFE>>        /// </summary>
BFE>>        /// <param name="t1">Заданное время</param>
BFE>>        /// <returns>Ближайший момент времени в расписании</returns>
BFE>>        public DateTime NearestEvent(DateTime t1)
BFE>>        {
BFE>>            // цикл проверки каждый раз после корректировки времени, макс. кол-во итераций: 100 + 11 + 31 + 23 + 59 + 59 = 283
BFE>>            while (true)
BFE>>            {
BFE>>                var yearOffset = t1.Year - 2000;
BFE>>                if ((yearOffset < 0) || (yearOffset >= _years.Length))
BFE>>                {
BFE>>                    throw new InvalidOperationException ("Year out of range");
BFE>>                }

BFE>>                if (_years[yearOffset] > 0)
BFE>>                {
BFE>>                    if (_months[t1.Month - 1] > 0)
BFE>>                    {
BFE>>                        var isLastDayInMonth = t1.Day == DateTime.DaysInMonth (t1.Year, t1.Month);
BFE>>                        // 32-й день означает последнее число месяца
BFE>>                        if (((_days[t1.Day - 1] > 0) || (isLastDayInMonth && (_days[31] > 0))) && (_weekDays[(int)t1.DayOfWeek] > 0))
BFE>>                        {
BFE>>                            if (_hours[t1.Hour] > 0)
BFE>>                            {
BFE>>                                if (_minutes[t1.Minute] > 0)
BFE>>                                {
BFE>>                                    if (_seconds[t1.Second] > 0)
BFE>>                                    {
BFE>>                                        var millisecond = t1.Millisecond;
BFE>>                                        do
BFE>>                                        {
BFE>>                                            if (_milliseconds[millisecond] > 0)
BFE>>                                            {
BFE>>                                                return new DateTime (t1.Year, t1.Month, t1.Day, t1.Hour, t1.Minute, t1.Second, millisecond);
BFE>>                                            }

BFE>>                                            millisecond++;
BFE>>                                        } while (millisecond < _milliseconds.Length);
BFE>>                                    }
BFE>>                                    t1 = new DateTime (t1.Year, t1.Month, t1.Day, t1.Hour, t1.Minute, t1.Second).AddSeconds (1);
BFE>>                                }
BFE>>                                else
BFE>>                                {
BFE>>                                    t1 = new DateTime (t1.Year, t1.Month, t1.Day, t1.Hour, t1.Minute, 0).AddMinutes (1);
BFE>>                                }
BFE>>                            }
BFE>>                            else
BFE>>                            {
BFE>>                                t1 = new DateTime (t1.Year, t1.Month, t1.Day, t1.Hour, 0, 0).AddHours (1);
BFE>>                            }
BFE>>                        }
BFE>>                        else
BFE>>                        {
BFE>>                            t1 = new DateTime (t1.Year, t1.Month, t1.Day).AddDays (1);
BFE>>                        }
BFE>>                    }
BFE>>                    else
BFE>>                    {
BFE>>                        t1 = new DateTime (t1.Year, t1.Month, 1).AddMonths (1);
BFE>>                    }
BFE>>                }
BFE>>                else
BFE>>                {
BFE>>                    t1 = new DateTime (t1.Year, 1, 1).AddYears (1);
BFE>>                }
BFE>>            }
BFE>>        }

BFE>>        /// <summary>
BFE>>        /// Возвращает предыдущий ближайший к заданному времени момент в расписании или
BFE>>        /// само заданное время, если оно есть в расписании.
BFE>>        /// </summary>
BFE>>        /// <param name="t1">Заданное время</param>
BFE>>        /// <returns>Ближайший момент времени в расписании</returns>
BFE>>        public DateTime NearestPrevEvent(DateTime t1)
BFE>>        {
BFE>>            // цикл проверки каждый раз после корректировки времени, макс. кол-во итераций: 100 + 11 + 31 + 23 + 59 + 59 = 283
BFE>>            while (true)
BFE>>            {
BFE>>                var yearOffset = t1.Year - 2000;
BFE>>                if ((yearOffset < 0) || (yearOffset >= _years.Length))
BFE>>                {
BFE>>                    throw new InvalidOperationException ("Year out of range");
BFE>>                }

BFE>>                if (_years[yearOffset] > 0)
BFE>>                {
BFE>>                    if (_months[t1.Month - 1] > 0)
BFE>>                    {
BFE>>                        var isLastDayInMonth = t1.Day == DateTime.DaysInMonth (t1.Year, t1.Month);
BFE>>                        // 32-й день означает последнее число месяца
BFE>>                        if (((_days[t1.Day - 1] > 0) || (isLastDayInMonth && (_days[31] > 0))) && (_weekDays[(int)t1.DayOfWeek] > 0))
BFE>>                        {
BFE>>                            if (_hours[t1.Hour] > 0)
BFE>>                            {
BFE>>                                if (_minutes[t1.Minute] > 0)
BFE>>                                {
BFE>>                                    if (_seconds[t1.Second] > 0)
BFE>>                                    {
BFE>>                                        var millisecond = t1.Millisecond;
BFE>>                                        do
BFE>>                                        {
BFE>>                                            if (_milliseconds[millisecond] > 0)
BFE>>                                            {
BFE>>                                                return new DateTime (t1.Year, t1.Month, t1.Day, t1.Hour, t1.Minute, t1.Second, millisecond);
BFE>>                                            }

BFE>>                                            millisecond--;
BFE>>                                        } while (millisecond >= 0);
BFE>>                                    }
BFE>>                                    t1 = new DateTime (t1.Year, t1.Month, t1.Day, t1.Hour, t1.Minute, t1.Second).AddMilliseconds (-1);
BFE>>                                }
BFE>>                                else
BFE>>                                {
BFE>>                                    t1 = new DateTime (t1.Year, t1.Month, t1.Day, t1.Hour, t1.Minute, 0).AddMilliseconds (-1);
BFE>>                                }
BFE>>                            }
BFE>>                            else
BFE>>                            {
BFE>>                                t1 = new DateTime (t1.Year, t1.Month, t1.Day, t1.Hour, 0, 0).AddMilliseconds (-1);
BFE>>                            }
BFE>>                        }
BFE>>                        else
BFE>>                        {
BFE>>                            t1 = new DateTime (t1.Year, t1.Month, t1.Day).AddMilliseconds (-1);
BFE>>                        }
BFE>>                    }
BFE>>                    else
BFE>>                    {
BFE>>                        t1 = new DateTime (t1.Year, t1.Month, 1).AddMilliseconds (-1);
BFE>>                    }
BFE>>                }
BFE>>                else
BFE>>                {
BFE>>                    t1 = new DateTime (t1.Year, 1, 1).AddMilliseconds (-1);
BFE>>                }
BFE>>            }
BFE>>        }

BFE>>        /// <summary>
BFE>>        /// Возвращает следующий момент времени в расписании.
BFE>>        /// </summary>
BFE>>        /// <param name="t1">Время, от которого нужно отступить</param>
BFE>>        /// <returns>Следующий момент времени в расписании</returns>
BFE>>        public DateTime NextEvent(DateTime t1)
BFE>>        {
BFE>>            return NearestEvent (t1.AddMilliseconds (1));
BFE>>        }

BFE>>        /// <summary>
BFE>>        /// Возвращает предыдущий момент времени в расписании.
BFE>>        /// </summary>
BFE>>        /// <param name="t1">Время, от которого нужно отступить</param>
BFE>>        /// <returns>Предыдущий момент времени в расписании</returns>
BFE>>        public DateTime PrevEvent(DateTime t1)
BFE>>        {
BFE>>            return NearestPrevEvent (t1.AddMilliseconds (-1));
BFE>>        }

BFE>>        /// <summary>
BFE>>        /// Заполняет указанный массив ненулевыми значениями для тех индексов, которые указаны в partStr.
BFE>>        /// </summary>
BFE>>        /// <param name="partStr">Текстовый список диапазонов.</param>
BFE>>        /// <param name="allowedValues">Массив, в котором будут отмечены ненулевым значением указанные в partStr числа.</param>
BFE>>        /// <param name="offset">Смещение, которое будет вычитаться для всех чисел, указанных в partStr.</param>
BFE>>        private static void ParsePart (ReadOnlySpan<char> partStr, byte[] allowedValues, int offset)
BFE>>        {
BFE>>            // Каждую часть даты/времени можно задавать в виде списков и диапазонов.
BFE>>            // Например:
BFE>>            //     1,2,3-5,10-20/3
BFE>>            //     означает список 1,2,3,4,5,10,13,16,19
BFE>>            // Дробью задается шаг в списке.
BFE>>            // Звездочка означает любое возможное значение.

BFE>>            if (partStr.Length < 1)
BFE>>            {
BFE>>                throw new FormatException ("Invalid part");
BFE>>            }

BFE>>            var idx = 0;
BFE>>            while (idx < partStr.Length)
BFE>>            {
BFE>>                int number1;
BFE>>                int number2;
BFE>>                if (partStr[idx] == '*')
BFE>>                {
BFE>>                    idx++;
BFE>>                    number1 = 0;
BFE>>                    number2 = allowedValues.Length - 1;
BFE>>                }
BFE>>                else
BFE>>                {
BFE>>                    number1 = ParseNumber (partStr, ref idx) - offset;
BFE>>                    if ((number1 < 0) || (number1 >= allowedValues.Length))
BFE>>                    {
BFE>>                        throw new FormatException ("Number out of range.");
BFE>>                    }

BFE>>                    number2 = number1;
BFE>>                    if ((idx < partStr.Length) && (partStr[idx] == '-'))
BFE>>                    {
BFE>>                        idx++;
BFE>>                        number2 = ParseNumber (partStr, ref idx) - offset;
BFE>>                        if ((number2 < 0) || (number2 >= allowedValues.Length))
BFE>>                        {
BFE>>                            throw new FormatException ("Number out of range.");
BFE>>                        }
BFE>>                    }
BFE>>                }

BFE>>                var period = 1;
BFE>>                if (idx < partStr.Length)
BFE>>                {
BFE>>                    switch (partStr[idx])
BFE>>                    {
BFE>>                        case '/':
BFE>>                            idx++;
BFE>>                            period = ParseNumber (partStr, ref idx);
BFE>>                            break;
BFE>>                        case ',':
BFE>>                            idx++;
BFE>>                            break;
BFE>>                        default:
BFE>>                            throw new FormatException ("Invalid character.");
BFE>>                    }
BFE>>                }

BFE>>                for (var i = number1; i <= number2; i += period)
BFE>>                {
BFE>>                    allowedValues[i] = 1;
BFE>>                }
BFE>>            }
BFE>>        }

BFE>>        // возвращает число, полученное из текстового представленая в partStr начиная с индекса в idx
BFE>>        private static int ParseNumber (ReadOnlySpan<char> partStr, ref int idx)
BFE>>        {
BFE>>            var number = 0;
BFE>>            while ((idx < partStr.Length) && (partStr[idx] >= '0') && (partStr[idx] <= '9'))
BFE>>            {
BFE>>                number = 10 * number + partStr[idx] - '0';
BFE>>                idx++;
BFE>>            }

BFE>>            return number;
BFE>>        }
BFE>>    }
BFE>>}
BFE>>



mgu>Какой вывих мозга?

А вы смогли сходу (за одно прочтение) понять, что и зачем делает автор?

mgu> Всё же совершенно очевидно:

mgu>
mgu>     // 32-й день означает последнее число месяца
mgu>

Это как раз да — это взято из условий.

mgu>Все возмущаются вложенностью условий... Да этот господин и одно-то условие не может написать толком:

А что не так?

mgu>
mgu>    if (((_days[t1.Day - 1] > 0) || (isLastDayInMonth && (_days[31] > 0))) && (_weekDays[(int)t1.DayOfWeek] > 0))
mgu>

mgu>Приоритет математических операций изучают во втором классе школы. Судя по правописанию, автор закончил только первый.
Я не знаю, как там оно в C#, поэтому мне со скобками проще читать. А как надо?
И каждый день — без права на ошибку...
Re[4]: Просидев на одном предприятии несколько лет...
От: B0FEE664  
Дата: 10.08.21 11:40
Оценка:
Здравствуйте, Sharov, Вы писали:

S>переложить большую часть проблем с учетом всяческих високосных годов на DataTime.

А разве это не так?
И каждый день — без права на ошибку...
Re[2]: Просидев на одном предприятии несколько лет...
От: B0FEE664  
Дата: 10.08.21 11:43
Оценка:
Здравствуйте, rosencrantz, Вы писали:

R>Здравствуйте, vaa, Вы писали:


vaa>>https://habr.com/ru/post/571342/

vaa>>Читаю комменты второй день и . Парадоксально на мой взгляд, но никто до сих пор(региться не охота)
vaa>>не отметил:
vaa>>1. быть может отказали почуяв крутого кулцхакера(конкурента).
vaa>>слышал в крупных компаниях есть такое ограничение — слишком умных не брать, чтобы не взломали систему.
vaa>>2. "Просидев на одном предприятии несколько лет...", таки зачем срываться? похоже на минутную слабость.
vaa>>3. почему-то все крутые прогеры пока только накидывают критики, но никто не показал образцовое решение.

R>Мне код не нравится — выглядит как "авторский".

Код реально авторский — не промышленный.

R>1. Для чтения выражений нужно какой-то внятный парсер с внятной грамматикой, или хотя бы регулярные выражения. Чтобы грамматика была не в комментах, а в чём-то более-менее компьютерном.

Это чтобы было сложнее тестировать или чтобы медленнее работал код?

R>Чтобы можно было красиво ругаться "что qwerty не выглядит как число от 1 до 12".

И что с этим потом делать?

R>2. Решение никак не порезано на отдельные логические куски — программу невозможно читать по частям, только как монолит. Я бы попытался дизайнить в сторону "композиции триггеров". Парсим -> дерево разбора -> составной триггер.

В один день уложитесь?
И каждый день — без права на ошибку...
Re[5]: Просидев на одном предприятии несколько лет...
От: Sharov Россия  
Дата: 10.08.21 11:50
Оценка:
Здравствуйте, B0FEE664, Вы писали:


S>>переложить большую часть проблем с учетом всяческих високосных годов на DataTime.

BFE>А разве это не так?

Я поверхностно пробежал, офигел от процедурного стиля и уровня вложений if, соотв. показалось, что он все делает руками. Т.е сам вычисляет условия високостного года и т.д. Могу и ошибаться.
Кодом людям нужно помогать!
Re[3]: Просидев на одном предприятии несколько лет...
От: rosencrantz США  
Дата: 10.08.21 17:08
Оценка:
Здравствуйте, B0FEE664, Вы писали:

R>>1. Для чтения выражений нужно какой-то внятный парсер с внятной грамматикой, или хотя бы регулярные выражения. Чтобы грамматика была не в комментах, а в чём-то более-менее компьютерном.

BFE>Это чтобы было сложнее тестировать или чтобы медленнее работал код?

На сложность тестирования это никак не влияет: тесты как были вход->выход, так и остаются. Про тормоза не стоит так вопрос ставить. Тормозит не код, тормозит система в конкретном ворклоаде. Использовать инструменты более высокого уровня (парсер против indexOf) стоит ради читаемости. Короткую регулярку (или десяток регулярок — по одной на каждый случай грамматики) прочитать и понять легче, чем эту лапшу из ифов и волшебных чисел.

Цитата из оригинальной статьи:

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


R>>Чтобы можно было красиво ругаться "что qwerty не выглядит как число от 1 до 12".

BFE>И что с этим потом делать?

Падать с эксшепшном "плохое выражение: qwerty не выглядит как число от 1 до 12" вместо "плохое выражение".

R>>2. Решение никак не порезано на отдельные логические куски — программу невозможно читать по частям, только как монолит. Я бы попытался дизайнить в сторону "композиции триггеров". Парсим -> дерево разбора -> составной триггер.

BFE>В один день уложитесь?

Нет, дня 3. А что?
Re[2]: Просидев на одном предприятии несколько лет...
От: ononim  
Дата: 10.08.21 19:59
Оценка:
AM>Зачем, например, под миллисекунды 1000 байт? По байту на каждое возможное значение? 60 байт на секунды, 60 на минуты и т.п. Зачем? Странный какой-то код у него.
Да ваще, экономист блин нашелся. BitArray-ем надо было.
Как много веселых ребят, и все делают велосипед...
Re[4]: Просидев на одном предприятии несколько лет...
От: mgu  
Дата: 10.08.21 22:05
Оценка:
Здравствуйте, Doom100500, Вы писали:

D>Здравствуйте, mgu, Вы писали:


mgu>>
mgu>>    if (((_days[t1.Day - 1] > 0) || (isLastDayInMonth && (_days[31] > 0))) && (_weekDays[(int)t1.DayOfWeek] > 0))
mgu>>


mgu>>Приоритет математических операций изучают во втором классе школы. Судя по правописанию, автор закончил только первый.


D>Это не математические, а логические оперзции. В школе их не изучают (по крайней мере не во втором классе).

D>А ставить скобки для удобочтаемости — это нормально.

А скобки и есть математические операции. От лишних скобок читаемость как раз страдает. Лучше бы в тексте про запятые не забывали.
Re[4]: Просидев на одном предприятии несколько лет...
От: mgu  
Дата: 10.08.21 22:24
Оценка:
Здравствуйте, B0FEE664, Вы писали:

mgu>>Какой вывих мозга?

BFE>А вы смогли сходу (за одно прочтение) понять, что и зачем делает автор?

Нет. А надо сходу?

mgu>> Всё же совершенно очевидно:

mgu>>
mgu>>     // 32-й день означает последнее число месяца
mgu>>

BFE>Это как раз да — это взято из условий.

Феерично! Тогда первый день месяца -- -1?

mgu>>Все возмущаются вложенностью условий... Да этот господин и одно-то условие не может написать толком:

BFE>А что не так?

mgu>>
mgu>>    if (((_days[t1.Day - 1] > 0) || (isLastDayInMonth && (_days[31] > 0))) && (_weekDays[(int)t1.DayOfWeek] > 0))
mgu>>

mgu>>Приоритет математических операций изучают во втором классе школы. Судя по правописанию, автор закончил только первый.
BFE>Я не знаю, как там оно в C#, поэтому мне со скобками проще читать.

А при чём здесь C#? Приоритет операций одинаков в большинстве ЯП.

BFE>А как надо?


Без бессмысленных скобок хотя бы так:
if ((_days[t1.Day - 1] > 0 || isLastDayInMonth && _days[31] > 0) && _weekDays[(int)t1.DayOfWeek] > 0)


А можно и так:
if (_days[isLastDayInMonth ? 31 : t1.Day - 1] > 0 && _weekDays[(int)t1.DayOfWeek] > 0)


А лучше вообще соорудить метод t1.isEmpty().
Re[4]: Просидев на одном предприятии несколько лет...
От: mgu  
Дата: 10.08.21 22:38
Оценка:
Здравствуйте, vfedosov, Вы писали:

mgu>>Приоритет математических операций изучают во втором классе школы. Судя по правописанию, автор закончил только первый.


V>Некоторые конторы заставляют ставить скобки вообще везде, где есть 2 операции и насрать им на приоритет. В Германии, к примеру, в атомобильной промышленности это просто индустриальный стандарт . Конечно, нечитабельно, но выхода нет — пишешь такое гавно.


Так дойдёт до:

a + (b * c)


Заметил, что кадровые говнокодеры, обычно пишушие в таком стиле:

a= 1;
b =2;
c = 3;


...за однострочный блок без фигурных скобок горло перегрызут.
Re[2]: Просидев на одном предприятии несколько лет...
От: vaa  
Дата: 11.08.21 01:45
Оценка:
Здравствуйте, scf, Вы писали:


scf>На хабре выложили интересный разбор решения и предложили "как надо" https://habr.com/ru/post/572052/


Т.е. даже прошаренному спецу понадобилось чуть больше недели чтобы заимплиментить задачу. да уж.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[3]: Просидев на одном предприятии несколько лет...
От: Тёмчик Австралия жж
Дата: 11.08.21 02:19
Оценка:
Здравствуйте, Блудов Павел, Вы писали:

scf>>P.S. И, конечно, сначала посмотрел бы, как умные люди это уже реализовали


БП>Не-не-не, не нужно смотреть. Там точно такая же простыня, но с регулярками.


Код на лиспе. Функции достаточно короткие. Сравни это с кодом автора, где 1 метод- гигантская простыня с кучей вложенных if-ов — else-ов.
Re[5]: Просидев на одном предприятии несколько лет...
От: Doom100500 Израиль  
Дата: 11.08.21 04:57
Оценка:
Здравствуйте, mgu, Вы писали:


mgu>Лучше бы в тексте про запятые не забывали.


Слив засчитан
Спасибо за внимание
Re[5]: Просидев на одном предприятии несколько лет...
От: Doom100500 Израиль  
Дата: 11.08.21 05:00
Оценка:
Здравствуйте, Тёмчик, Вы писали:

Тё>(наркоманы все как один хотят скобки для удобочитаемости).


К сожаению аргументов у меня нет, поэтому сразу перехожу на личности.
Спасибо за внимание
Re[5]: Просидев на одном предприятии несколько лет...
От: Doom100500 Израиль  
Дата: 11.08.21 05:05
Оценка:
Здравствуйте, mgu, Вы писали:

mgu>А можно и так:

mgu>
mgu>if (_days[isLastDayInMonth ? 31 : t1.Day - 1] > 0 && _weekDays[(int)t1.DayOfWeek] > 0)
mgu>


Вот это вообще зашквар

mgu>>>
mgu>>>    if (((_days[t1.Day - 1] > 0) || (isLastDayInMonth && (_days[31] > 0))) && (_weekDays[(int)t1.DayOfWeek] > 0))
mgu>>>


Как, в принципе и в оригинале. (Извините погoрячился)
Спасибо за внимание
Отредактировано 11.08.2021 5:33 Doom100500 . Предыдущая версия .
Re[5]: Просидев на одном предприятии несколько лет...
От: Doom100500 Израиль  
Дата: 11.08.21 05:31
Оценка:
Здравствуйте, mgu, Вы писали:

mgu>А скобки и есть математические операции.


А разве речь не шла о приоритете логических операций?
Продолжаю сомневаться, что это изучают во втором классе школы.
Спасибо за внимание
Re[2]: Просидев на одном предприятии несколько лет...
От: vaa  
Дата: 11.08.21 08:02
Оценка:
Здравствуйте, elmal, Вы писали:

E>И это у автора было до черта времени


Выполнив задание примерно за сутки


Это много? тут чуть выше написали появился альтернативный вариант, который "намного" лучше
но спустя 5 дней.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[4]: Просидев на одном предприятии несколько лет...
От: B0FEE664  
Дата: 11.08.21 08:24
Оценка:
Здравствуйте, rosencrantz, Вы писали:

R>>>1. Для чтения выражений нужно какой-то внятный парсер с внятной грамматикой, или хотя бы регулярные выражения. Чтобы грамматика была не в комментах, а в чём-то более-менее компьютерном.

BFE>>Это чтобы было сложнее тестировать или чтобы медленнее работал код?

R>На сложность тестирования это никак не влияет: тесты как были вход->выход, так и остаются.

Не совсем. При разборе входных данных важно, чтобы отбрасывались строки не подходящие по формату (иначе могут быть падения или другие неприятности). Например, очень многие парсеры json падают при правильно подобранной строке. Если парсер написан по простому — то его можно на 100% кода покрыть тестами: обычно этого достаточно, чтобы не было падений (но не спасёт от бесконечного цикла), а вот протестировать таким образом регулярные выражения не получится.

R>Про тормоза не стоит так вопрос ставить. Тормозит не код, тормозит система в конкретном ворклоаде.

Т.е. вы считаете, что для задачи которая оперирует с миллисекундами скорость не важна?
Или, может, точно известно, что это не мобильное устройство и батарейку экономить не надо?

R>Использовать инструменты более высокого уровня (парсер против indexOf) стоит ради читаемости. Короткую регулярку (или десяток регулярок — по одной на каждый случай грамматики) прочитать и понять легче, чем эту лапшу из ифов и волшебных чисел.

Конечно, это реализация разбора трудна для чтения и такой код недопустим, однако это никак не означает, что следует использовать регулярные выражения.

R>Цитата из оригинальной статьи:

R>

R>Добиваться каких то экстремальных показателей в плане оптимизации нет смысла, потому что это приведёт к снижению такого важного показателя как поддерживаемость кода, а будет ли от этого польза — непонятно, поскольку неизвестны условия эксплуатации.

Автор ошибается. В условиях сказано:

класс должен быть эффективным и не использовать много памяти и ресурсов даже тогда, когда в расписании задано много значений.


R>>>Чтобы можно было красиво ругаться "что qwerty не выглядит как число от 1 до 12".

BFE>>И что с этим потом делать?
R>Падать с эксшепшном "плохое выражение: qwerty не выглядит как число от 1 до 12" вместо "плохое выражение".
Не стоит забывать, что это тестовое задание, а не рабочий код.

R>>>2. Решение никак не порезано на отдельные логические куски — программу невозможно читать по частям, только как монолит. Я бы попытался дизайнить в сторону "композиции триггеров". Парсим -> дерево разбора -> составной триггер.

BFE>>В один день уложитесь?
R>Нет, дня 3. А что?
А то, что это тестовое задание, за которое денег не заплатят.
И каждый день — без права на ошибку...
Re[5]: Просидев на одном предприятии несколько лет...
От: B0FEE664  
Дата: 11.08.21 09:13
Оценка:
Здравствуйте, mgu, Вы писали:

mgu>>>Какой вывих мозга?

BFE>>А вы смогли сходу (за одно прочтение) понять, что и зачем делает автор?
mgu>Нет. А надо сходу?
Да, если код не является экстремальной оптимизацией.

mgu>>> Всё же совершенно очевидно:

mgu>>>
mgu>>>     // 32-й день означает последнее число месяца
mgu>>>

BFE>>Это как раз да — это взято из условий.
mgu>Феерично! Тогда первый день месяца -- -1?
Первый день месяца 0 ( хотя в комментах и написано другое ), следовательно индекс 31 — это 32-ой день.

mgu>А при чём здесь C#? Приоритет операций одинаков в большинстве ЯП.

Всякое бывает.

mgu>Без бессмысленных скобок хотя бы так:

Расставление скобок может регулироваться внутренними документами компании.
И каждый день — без права на ошибку...
Re[5]: Просидев на одном предприятии несколько лет...
От: Stanislav V. Zudin Россия  
Дата: 11.08.21 09:31
Оценка:
Здравствуйте, mgu, Вы писали:

mgu>Так дойдёт до:


mgu>
mgu>a + (b * c)
mgu>


Если читать удобнее, то почему нет?

mgu>Заметил, что кадровые говнокодеры, обычно пишушие в таком стиле:


mgu>
mgu>a= 1;
mgu>b =2;
mgu>c = 3;
mgu>


Вместо богомерзкой IDE код пишут в теплом ламповом vi?

mgu>...за однострочный блок без фигурных скобок горло перегрызут.


Правильно, ибо ходить под отладчиком без скобок неудобно — хрен угадаешь, почему отладчик прыгнул на строчку ниже — то ли цикл закончился, то ли он так конец блока обозначает.
_____________________
С уважением,
Stanislav V. Zudin
Re[5]: Просидев на одном предприятии несколько лет...
От: Sharov Россия  
Дата: 11.08.21 12:23
Оценка:
Здравствуйте, B0FEE664, Вы писали:


R>>На сложность тестирования это никак не влияет: тесты как были вход->выход, так и остаются.

BFE>Не совсем. При разборе входных данных важно, чтобы отбрасывались строки не подходящие по формату (иначе могут быть падения или другие неприятности). Например, очень многие парсеры json падают при правильно подобранной строке. Если парсер написан по простому — то его можно на 100% кода покрыть тестами: обычно этого достаточно, чтобы не было падений (но не спасёт от бесконечного цикла), а вот протестировать таким образом регулярные выражения не получится.

Это почему? Что может быть проще чем протестировать конечный автомат?
Кодом людям нужно помогать!
Re[5]: Просидев на одном предприятии несколько лет...
От: rosencrantz США  
Дата: 11.08.21 13:52
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Здравствуйте, rosencrantz, Вы писали:


R>>>>1. Для чтения выражений нужно какой-то внятный парсер с внятной грамматикой, или хотя бы регулярные выражения. Чтобы грамматика была не в комментах, а в чём-то более-менее компьютерном.

BFE>>>Это чтобы было сложнее тестировать или чтобы медленнее работал код?

R>>На сложность тестирования это никак не влияет: тесты как были вход->выход, так и остаются.

BFE>Не совсем. При разборе входных данных важно, чтобы отбрасывались строки не подходящие по формату (иначе могут быть падения или другие неприятности). Например, очень многие парсеры json падают при правильно подобранной строке. Если парсер написан по простому — то его можно на 100% кода покрыть тестами: обычно этого достаточно, чтобы не было падений (но не спасёт от бесконечного цикла), а вот протестировать таким образом регулярные выражения не получится.

Это мифы и легенды. И регулярками пользуются, и парсеры пишут. В данной конкретной ситуации нет каких-то реальных причин, их не использовать. Можно додумать нереальные конечно.

R>>Про тормоза не стоит так вопрос ставить. Тормозит не код, тормозит система в конкретном ворклоаде.

BFE>Т.е. вы считаете, что для задачи которая оперирует с миллисекундами скорость не важна?
BFE>Или, может, точно известно, что это не мобильное устройство и батарейку экономить не надо?

Глобальное потепление ещё забыли. Ваша мифическая система 99% времени занимается разбором расписаний и 1% времени — вычислениями таймстемпов следующих/предыдущих ивентов? Мы поэтому обсуждаем тормоза регулярок, да?

R>>Использовать инструменты более высокого уровня (парсер против indexOf) стоит ради читаемости. Короткую регулярку (или десяток регулярок — по одной на каждый случай грамматики) прочитать и понять легче, чем эту лапшу из ифов и волшебных чисел.

BFE>Конечно, это реализация разбора трудна для чтения и такой код недопустим, однако это никак не означает, что следует использовать регулярные выражения.

См выше.

R>>Цитата из оригинальной статьи:

R>>

R>>Добиваться каких то экстремальных показателей в плане оптимизации нет смысла, потому что это приведёт к снижению такого важного показателя как поддерживаемость кода, а будет ли от этого польза — непонятно, поскольку неизвестны условия эксплуатации.

BFE>Автор ошибается. В условиях сказано:
BFE>

BFE>класс должен быть эффективным и не использовать много памяти и ресурсов даже тогда, когда в расписании задано много значений.


Не использовать много памяти — это сколько? Много значений — это сколько? Я из написанного этого прочитать не могу, поэтому интерпретирую как "используйте здравый смысл". Вы прямо микроконтроллер c 4кб памяти разглядели?

R>>>>Чтобы можно было красиво ругаться "что qwerty не выглядит как число от 1 до 12".

BFE>>>И что с этим потом делать?
R>>Падать с эксшепшном "плохое выражение: qwerty не выглядит как число от 1 до 12" вместо "плохое выражение".
BFE>Не стоит забывать, что это тестовое задание, а не рабочий код.

"Ну это же тестовое задание, поэтому плохой код допустим", "ну у нас же дедлайн завтра, поэтому плохой код допустим", "демо через 15 минут, поэтому я буду коммитить в мастер без пулриквестов".

R>>>>2. Решение никак не порезано на отдельные логические куски — программу невозможно читать по частям, только как монолит. Я бы попытался дизайнить в сторону "композиции триггеров". Парсим -> дерево разбора -> составной триггер.

BFE>>>В один день уложитесь?
R>>Нет, дня 3. А что?
BFE>А то, что это тестовое задание, за которое денег не заплатят.

Если у человека есть стандарты качества, и он видит, что при таких стандартах задача займёт больше, чем кажется допустимым, всегда можно отказаться. Можно не отказаться, можно сделать какашку, что мы и наблюдаем. Управление проектами в СД в жопе отчасти именно из-за таких вот ребят: я и хреновую постановку задачи приму, и ещё наобещаю за 1 день сделать, а потом ту дрянь, которая получилась, я буду отмазывать именно этим 1 днём, плохой постановкой задачи, стрессом.

Это ведь каким токсичным засранцем надо быть, чтобы требовать возможности проговорить требования и послать всех подальше, если отказываются обсуждать, да? Прикинуть сколько займёт нормальное решение задачи — за которое не стыдно, которое можно читать и расширять, удивиться, что выходит неделя и снова — либо предложить нанимающей компании оплатить это по адекватному рейту, или послать нафиг компанию, если отказываются? Это ведь совсем отморозком нужно быть, в цивилизованном обществе 21 века у нас так не принято, да?

Но автор статьи не такой — товарищ согласился забесплатно без нормальной постановки задачи что-то изобразить за 1 день.
Re[3]: Просидев на одном предприятии несколько лет...
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 11.08.21 18:43
Оценка:
Здравствуйте, vaa, Вы писали:

vaa>Мне одному кажется, что "как надо" не лучше, чем "как получилось" по большому счёту?

Мне вот не кажется. Идея с парсер-комбинаторами — огонь (признаюсь, первый раз про это слышу). Очевидно, по скорости оно отстаёт от ручного разбора, но читабельность и гибкость решает.
Sic luceat lux!
Re[6]: Просидев на одном предприятии несколько лет...
От: mgu  
Дата: 11.08.21 21:42
Оценка:
Здравствуйте, Doom100500, Вы писали:

D>Здравствуйте, mgu, Вы писали:


mgu>>А можно и так:

mgu>>
mgu>>if (_days[isLastDayInMonth ? 31 : t1.Day - 1] > 0 && _weekDays[(int)t1.DayOfWeek] > 0)
mgu>>


D>Вот это вообще зашквар


В конце предложения подразумевалась точка или двоеточие?

mgu>>>>
mgu>>>>    if (((_days[t1.Day - 1] > 0) || (isLastDayInMonth && (_days[31] > 0))) && (_weekDays[(int)t1.DayOfWeek] > 0))
mgu>>>>


D>Как, в принципе и в оригинале. (Извините погoрячился)


Пропущены 2 запятые. Читаемость!
Re[6]: Просидев на одном предприятии несколько лет...
От: mgu  
Дата: 11.08.21 21:43
Оценка:
Здравствуйте, Doom100500, Вы писали:

D>Здравствуйте, mgu, Вы писали:


mgu>>А скобки и есть математические операции.


D>А разве речь не шла о приоритете логических операций?

D>Продолжаю сомневаться, что это изучают во втором классе школы.

Речь щла о базовом классе "математические операции".
Re[6]: Просидев на одном предприятии несколько лет...
От: mgu  
Дата: 11.08.21 22:34
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>>>А вы смогли сходу (за одно прочтение) понять, что и зачем делает автор?

mgu>>Нет. А надо сходу?
BFE>Да, если код не является экстремальной оптимизацией.

Я даже техзадания не могу прочитать сходу.

mgu>>>> Всё же совершенно очевидно:

mgu>>>>
mgu>>>>     // 32-й день означает последнее число месяца
mgu>>>>

BFE>>>Это как раз да — это взято из условий.
mgu>>Феерично! Тогда первый день месяца -- -1?
BFE>Первый день месяца 0 ( хотя в комментах и написано другое ), следовательно индекс 31 — это 32-ой день.

Я бы для проверки последнего дня месяца (при отсутствии встроенного метода), просто прибавлял бы к дате 1 день и проверял бы на первое число.

mgu>>Без бессмысленных скобок хотя бы так:

BFE>Расставление скобок может регулироваться внутренними документами компании.

Может. Но это было тестовое задание.
Re[6]: Просидев на одном предприятии несколько лет...
От: mgu  
Дата: 11.08.21 22:53
Оценка:
Здравствуйте, Stanislav V. Zudin, Вы писали:

SVZ>Здравствуйте, mgu, Вы писали:


mgu>>Так дойдёт до:


mgu>>
mgu>>a + (b * c)
mgu>>


SVZ>Если читать удобнее, то почему нет?


Кому удобнее? По мне так чем меньше лишнего, тем лучше. Выход в стандартах. И опять же, любители "читаемости" обычно игнорируют запятые и прописные буквы в тексте.

mgu>>Заметил, что кадровые говнокодеры, обычно пишушие в таком стиле:


mgu>>
mgu>>a= 1;
mgu>>b =2;
mgu>>c = 3;
mgu>>


SVZ>Вместо богомерзкой IDE код пишут в теплом ламповом vi?


Автоформатирование появилось не так давно.

mgu>>...за однострочный блок без фигурных скобок горло перегрызут.


SVZ>Правильно, ибо ходить под отладчиком без скобок неудобно — хрен угадаешь, почему отладчик прыгнул на строчку ниже — то ли цикл закончился, то ли он так конец блока обозначает.


Это рассогласование исполняемого файла и исходного кода.

В моих богомерзких IDE всё нормально работает.
Re[4]: Просидев на одном предприятии несколько лет...
От: vaa  
Дата: 12.08.21 15:29
Оценка:
Здравствуйте, Kernan, Вы писали:

K>Мне вот не кажется. Идея с парсер-комбинаторами — огонь (признаюсь, первый раз про это слышу). Очевидно, по скорости оно отстаёт от ручного разбора, но читабельность и гибкость решает.

Сразу не увидел, парсер у него готовый. ну да ладно.
я бы наверно просто сплитом разбил на 3 части сначала по пробелу, потом дату по точкам, т.е. раздробил бы на мелкие части.
можно красиво оформить флуентом, формат очень четко описан. стабилен так сказать.
еще бросилось в глаза что год с 2000 начинаться должен. т.е. задание вероятно очень древнее. сравнили со своей реализацией.
свое понравилось больше )))
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[8]: Просидев на одном предприятии несколько лет...
От: mgu  
Дата: 12.08.21 15:47
Оценка:
Здравствуйте, Doom100500, Вы писали:

mgu>>В конце предложения подразумевалась точка или двоеточие?


mgu>>Пропущены 2 запятые. Читаемость!


D>Т.е. когда сказать нечего, то вполне приемлемо попридираться к запятым и точкам.


Сказать есть что, но сперва нужно понять ваше "казнить нельзя помиловать".

mgu>>Речь щла о базовом классе "математические операции".


D>Вот это поворот! (В конце восклицательный знак )


Логические операции -- это ваша идея.

D>Раз уж здесь принято переводить стрелки, то ловите, уважаемый:


mgu>>Я даже техзадания не могу прочитать сходу.


mgu>>Автоформатирование появилось не так давно.


D>Спад умственных способностей и жизнь в прошлом вполне себе являются признаками ранней деменции. Пора начинать беспокоиться.


"Появилось не так давно" подразумевает сравнение прошлого и настоящего. Начинайте беспокоиться.
Re[4]: Просидев на одном предприятии несколько лет...
От: vsb Казахстан  
Дата: 12.08.21 22:26
Оценка:
Здравствуйте, B0FEE664, Вы писали:

mgu>>Приоритет математических операций изучают во втором классе школы. Судя по правописанию, автор закончил только первый.

BFE>Я не знаю, как там оно в C#, поэтому мне со скобками проще читать. А как надо?

А надо выучить язык, который используешь и не использовать скобки там, где они не нужны, чтобы не путать людей.
Re[3]: Просидев на одном предприятии несколько лет...
От: B0FEE664  
Дата: 13.08.21 08:27
Оценка:
Здравствуйте, mgu, Вы писали:

scf>>На хабре выложили интересный разбор решения и предложили "как надо" https://habr.com/ru/post/572052/


mgu>Я наверно пропустил, там конкурс на лучшего говнокодера?

Похоже на то.
mgu>Говнокодерство заразно!
Ещё два-три таких улучшения и код станет совершенно невозможно прочесть.
И каждый день — без права на ошибку...
Re[4]: Просидев на одном предприятии несколько лет...
От: B0FEE664  
Дата: 13.08.21 09:00
Оценка:
Здравствуйте, Тёмчик, Вы писали:

scf>>>P.S. И, конечно, сначала посмотрел бы, как умные люди это уже реализовали

БП>>Не-не-не, не нужно смотреть. Там точно такая же простыня, но с регулярками.
Тё>Код на лиспе. Функции достаточно короткие. Сравни это с кодом автора, где 1 метод- гигантская простыня с кучей вложенных if-ов — else-ов.

А ещё надо время выполнения сравнить...
И каждый день — без права на ошибку...
Re[6]: Просидев на одном предприятии несколько лет...
От: B0FEE664  
Дата: 13.08.21 09:50
Оценка:
Здравствуйте, rosencrantz, Вы писали:

R>Это мифы и легенды. И регулярками пользуются, и парсеры пишут. В данной конкретной ситуации нет каких-то реальных причин, их не использовать. Можно додумать нереальные конечно.

Пользуются, только потом таким софтом пользоваться не приятно. К примеру, что будет если задать расписание:
"2021.12.12 00:11:99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999.5555"
Приложение не упадёт? А если строку увеличить до магабайта? Отработает корректно? Ну ладно, это строка не корректна. Возьмём корректный пример. Так... Длина строки не ограничена никак, тогда... Используем список:
"2021.12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12.12 00:11:22.999"

Таких ",12" можно задать, скажем, 12 миллионов. (Если, например, выдумать, что расписание генерируется скриптом на основе данных взятых из базы, то почему бы и нет?) Вы всё ещё уверены в своих регулярках?

R>>>Про тормоза не стоит так вопрос ставить. Тормозит не код, тормозит система в конкретном ворклоаде.

BFE>>Т.е. вы считаете, что для задачи которая оперирует с миллисекундами скорость не важна?
BFE>>Или, может, точно известно, что это не мобильное устройство и батарейку экономить не надо?

R>Глобальное потепление ещё забыли.

Если задача выполняется на сотнях тысячах компьютеров десятки лет...

R>Ваша мифическая система 99% времени занимается разбором расписаний и 1% времени — вычислениями таймстемпов следующих/предыдущих ивентов? Мы поэтому обсуждаем тормоза регулярок, да?

Допустим нам надо сэкономить память, потому что у нас десятки тысяч таких расписаний.
Как это сделать?
Есть простой способ: вместо того, чтобы хранить массивы _years, _months, ... можно хранить только строку расписания, а при каждом вызове для следующих/предыдущих ивентов разбирать эту строку в массивы лежащие на стеке. Тогда, если разбор быстрый — то всё получится, а вот если медленный — придётся переписывать.

BFE>>Автор ошибается. В условиях сказано:

BFE>>

BFE>>класс должен быть эффективным и не использовать много памяти и ресурсов даже тогда, когда в расписании задано много значений.


R>Не использовать много памяти — это сколько? Много значений — это сколько? Я из написанного этого прочитать не могу, поэтому интерпретирую как "используйте здравый смысл". Вы прямо микроконтроллер c 4кб памяти разглядели?


Тут без включения телепатии и знания области в которой работает контора узнать не возможно. Однако, обычно, известно что делает контора в которую пытаешься устроится, поэтому можно сделать некоторые предположения.

R>>>>>Чтобы можно было красиво ругаться "что qwerty не выглядит как число от 1 до 12".

BFE>>>>И что с этим потом делать?
R>>>Падать с эксшепшном "плохое выражение: qwerty не выглядит как число от 1 до 12" вместо "плохое выражение".
BFE>>Не стоит забывать, что это тестовое задание, а не рабочий код.
R>"Ну это же тестовое задание, поэтому плохой код допустим",
В нормальной программе падение вообще не допустимо.

R>"ну у нас же дедлайн завтра, поэтому плохой код допустим", "демо через 15 минут, поэтому я буду коммитить в мастер без пулриквестов".

К чему это написано?

R>Это ведь каким токсичным засранцем надо быть, чтобы требовать возможности проговорить требования и послать всех подальше, если отказываются обсуждать, да? Прикинуть сколько займёт нормальное решение задачи — за которое не стыдно, которое можно читать и расширять, удивиться, что выходит неделя и снова — либо предложить нанимающей компании оплатить это по адекватному рейту, или послать нафиг компанию, если отказываются? Это ведь совсем отморозком нужно быть, в цивилизованном обществе 21 века у нас так не принято, да?

Ну да, компания "токсичная". С такими просто: сначала договариваешься о такой зарплате, при которой сделать бесплатный тест не лень, а потом делаешь тест. Только так, не наоборот. Впрочем, в таких компаниях как только слышат о том, сколько хочешь получать, так сразу отказывают, без тестового задания.

R>Но автор статьи не такой — товарищ согласился забесплатно без нормальной постановки задачи что-то изобразить за 1 день.

Автор тренируется перед началом нормального поиска. Обычное дело.
И каждый день — без права на ошибку...
Re[7]: Просидев на одном предприятии несколько лет...
От: rosencrantz США  
Дата: 13.08.21 14:13
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Здравствуйте, rosencrantz, Вы писали:


R>>Это мифы и легенды. И регулярками пользуются, и парсеры пишут. В данной конкретной ситуации нет каких-то реальных причин, их не использовать. Можно додумать нереальные конечно.

BFE>Пользуются, только потом таким софтом пользоваться не приятно. К примеру, что будет если задать расписание:
...
BFE>Приложение не упадёт? А если строку увеличить до магабайта? Отработает корректно? Ну ладно, это строка не корректна. Возьмём корректный пример. Так... Длина строки не ограничена никак, тогда... Используем список:

вот не знаю зачем я вообще писал: "можно додумать нереальные конечно". Анекдот про суровых сибирских мужиков.

BFE>Таких ",12" можно задать, скажем, 12 миллионов. (Если, например, выдумать, что расписание генерируется скриптом на основе данных взятых из базы, то почему бы и нет?) Вы всё ещё уверены в своих регулярках?


Чего уж там, давайте сразу 10^1234

R>>Ваша мифическая система 99% времени занимается разбором расписаний и 1% времени — вычислениями таймстемпов следующих/предыдущих ивентов? Мы поэтому обсуждаем тормоза регулярок, да?

BFE>Допустим нам надо сэкономить память, потому что у нас десятки тысяч таких расписаний.
BFE>Как это сделать?
BFE>Есть простой способ: вместо того, чтобы хранить массивы _years, _months, ... можно хранить только строку расписания, а при каждом вызове для следующих/предыдущих ивентов разбирать эту строку в массивы лежащие на стеке. Тогда, если разбор быстрый — то всё получится, а вот если медленный — придётся переписывать.

Вот она — конкретная система с конкретным ворклоадом. Только ведь вы её с потолка взяли — к исходной задаче это отношения не имеет.

Что будете делать если быстрый разбор в реальности оказажется недостаточно быстр ("у нас тут миллисекунды же")?

R>>Не использовать много памяти — это сколько? Много значений — это сколько? Я из написанного этого прочитать не могу, поэтому интерпретирую как "используйте здравый смысл". Вы прямо микроконтроллер c 4кб памяти разглядели?


BFE>Тут без включения телепатии и знания области в которой работает контора узнать не возможно. Однако, обычно, известно что делает контора в которую пытаешься устроится, поэтому можно сделать некоторые предположения.


Чего уж там, давайте сразу зашпионим проверяльщика задания и выясним какие книжки он читал за последние полгода
Re[4]: Просидев на одном предприятии несколько лет...
От: sergey2b ЮАР  
Дата: 13.08.21 16:07
Оценка:
Здравствуйте, Gradiens, Вы писали:


G>Смотри, я как соискатель просто не хочу тратить время на задание. Потому что за это время смогу пройти 2-3 интервью.

G>Я как работодатель не хочу тратить время на разбор чьих-то каракуль. Мне и на моем проекте хватает код-ревью. Я лучше дам человеку пример кода на 1 экран и попрошу проревьювить. И за 10-15 мин станет ясно, имеет ли смысл дальнейший диалог.

G>Так что никто не хочет ))


говорят что те читает и понимает
не всегда могут писать нормально
Re[4]: Просидев на одном предприятии несколько лет...
От: Venom  
Дата: 13.08.21 16:14
Оценка:
Здравствуйте, Gradiens, Вы писали:

G>Так что никто не хочет ))

Никто не хочет думать, да, потому что как говорил, кажется, Форд: "Думать — это самое сложное (трудное)".
И продолжение цитаты: "Вот, наверное, почему так мало людей этим занимается".
Всё сходится.
Re[4]: Просидев на одном предприятии несколько лет...
От: SkyKnight Швейцария https://github.com/dmitrigrigoriev/
Дата: 30.08.21 11:09
Оценка:
Здравствуйте, elmal, Вы писали:

E>Во первых там не все 5 дней на фултайме делали. Уверен что на альтернативный вариант максимум час потратили, ибо неимоверно лень.

6-8 часов по словам автора "как надо"
github.com/dmitrigrigoriev/
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.