← Назад к вопросам

Функция определения пересечения двух интервалов

2.0 Middle🔥 121 комментариев
#Стандарты разработки

Условие

Напишите функцию, которая определяет факт пересечения двух интервалов.

Интервалы могут быть заданы с открытыми и закрытыми границами:

  • ( или ) - открытая граница (значение не включено)
  • [ или ] - закрытая граница (значение включено)

Пример

Вход: интервал1 = (-2; 3), интервал2 = [3; 5] Выход: Ложь (так как 3 не входит в первый интервал)

Вход: интервал1 = [-2; 3], интервал2 = [3; 5] Выход: Истина (так как 3 входит в оба интервала)

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Решение

Обзор задачи

Задача требует определить, пересекаются ли два интервала с учётом типов границ (открытые и закрытые). Это важно для обработки числовых диапазонов в 1С, например при работе с расписанием, ценовыми диапазонами или временными окнами.

Математическая основа

Два интервала пересекаются, если:

  • Левая граница одного интервала меньше правой границы другого
  • Правая граница одного интервала больше левой границы другого

При сравнении нужно учитывать тип границ (открытая/закрытая).

Реализация на 1С

Функция ПересекаютсяИнтервалы(Интервал1, Интервал2)
    // Парсим первый интервал
    Граница1Лева = Интервал1[0]; // Символ скобки
    Значение1Лева = Интервал1[1]; // Число
    Значение1Права = Интервал1[2]; // Число
    Граница1Права = Интервал1[3]; // Символ скобки
    
    // Парсим второй интервал
    Граница2Лева = Интервал2[0];
    Значение2Лева = Интервал2[1];
    Значение2Права = Интервал2[2];
    Граница2Права = Интервал2[3];
    
    // Определяем левую и правую границы общего пересечения
    ПересечениеЛева = Макс(Значение1Лева, Значение2Лева);
    ПересечениеПрава = Мин(Значение1Права, Значение2Права);
    
    // Если левая граница явно больше правой - нет пересечения
    Если ПересечениеЛева > ПересечениеПрава Тогда
        Возврат Ложь;
    КонецЕсли;
    
    // Если левая граница равна правой - проверяем открытость границ
    Если ПересечениеЛева = ПересечениеПрава Тогда
        // Определяем открытость границы слева
        ОткрытаГраницаСлева = Ложь;
        Если ПересечениеЛева = Значение1Лева И (Граница1Лева = "(" ИЛИ Граница1Лева = ")") Тогда
            ОткрытаГраницаСлева = Истина;
        КонецЕсли;
        Если ПересечениеЛева = Значение2Лева И (Граница2Лева = "(" ИЛИ Граница2Лева = ")") Тогда
            ОткрытаГраницаСлева = Истина;
        КонецЕсли;
        
        // Определяем открытость границы справа
        ОткрытаГраницаСправа = Ложь;
        Если ПересечениеПрава = Значение1Права И (Граница1Права = ")" ИЛИ Граница1Права = "(") Тогда
            ОткрытаГраницаСправа = Истина;
        КонецЕсли;
        Если ПересечениеПрава = Значение2Права И (Граница2Права = ")" ИЛИ Граница2Права = "(") Тогда
            ОткрытаГраницаСправа = Истина;
        КонецЕсли;
        
        // Если обе границы открыты - нет пересечения
        Если ОткрытаГраницаСлева И ОткрытаГраницаСправа Тогда
            Возврат Ложь;
        КонецЕсли;
    КонецЕсли;
    
    Возврат Истина;
КонецФункции

Улучшенная версия с помощником функцией

Функция ПарсИнтервала(СтрокаИнтервала)
    // Извлекаем скобки и числа из строки вида "(-2; 3)" или "[-2; 3]"
    СтрокаОчищенная = СтрОкончание(СтрокаИнтервала, 1); // Последняя скобка
    ГраницаПрава = СтрОкончание(СтрокаИнтервала, 1);
    
    СтрокаБезПосле = Лево(СтрокаИнтервала, СтрДлина(СтрокаИнтервала) - 1);
    ГраницаЛева = Лево(СтрокаБезПосле, 1);
    
    СтрокаЧисел = Середина(СтрокаБезПосле, 2);
    
    // Разбиваем по разделителю ";" или ","
    Позиция = Найти(СтрокаЧисел, ";");
    Если Позиция = 0 Тогда
        Позиция = Найти(СтрокаЧисел, ",");
    КонецЕсли;
    
    ЗначениеЛева = Число(Триум(Лево(СтрокаЧисел, Позиция - 1)));
    ЗначениеПрава = Число(Триум(Середина(СтрокаЧисел, Позиция + 1)));
    
    Возврат Новый Структура(
        "ГраницаЛева, ЗначениеЛева, ЗначениеПрава, ГраницаПрава",
        ГраницаЛева, ЗначениеЛева, ЗначениеПрава, ГраницаПрава);
КонецФункции

Функция ПересекаютсяИнтервалыУлучшенная(Интервал1, Интервал2)
    Инт1 = ПарсИнтервала(Интервал1);
    Инт2 = ПарсИнтервала(Интервал2);
    
    ЛеваяТочка = Макс(Инт1.ЗначениеЛева, Инт2.ЗначениеЛева);
    ПраваяТочка = Мин(Инт1.ЗначениеПрава, Инт2.ЗначениеПрава);
    
    Если ЛеваяТочка > ПраваяТочка Тогда
        Возврат Ложь;
    КонецЕсли;
    
    Если ЛеваяТочка = ПраваяТочка Тогда
        // Проверяем открытость
        КоличествоОткрытых = 0;
        
        Если ЛеваяТочка = Инт1.ЗначениеЛева И Инт1.ГраницаЛева = "(" Тогда
            КоличествоОткрытых = КоличествоОткрытых + 1;
        КонецЕсли;
        Если ЛеваяТочка = Инт2.ЗначениеЛева И Инт2.ГраницаЛева = "(" Тогда
            КоличествоОткрытых = КоличествоОткрытых + 1;
        КонецЕсли;
        
        Если ПраваяТочка = Инт1.ЗначениеПрава И Инт1.ГраницаПрава = ")" Тогда
            КоличествоОткрытых = КоличествоОткрытых + 1;
        КонецЕсли;
        Если ПраваяТочка = Инт2.ЗначениеПрава И Инт2.ГраницаПрава = ")" Тогда
            КоличествоОткрытых = КоличествоОткрытых + 1;
        КонецЕсли;
        
        Возврат КоличествоОткрытых < 2;
    КонецЕсли;
    
    Возврат Истина;
КонецФункции

Примеры использования

// Пример 1: (-2; 3) и [3; 5] - не пересекаются
Результат1 = ПересекаютсяИнтервалыУлучшенная("(-2; 3)", "[3; 5]"); // Ложь

// Пример 2: [-2; 3] и [3; 5] - пересекаются в точке 3
Результат2 = ПересекаютсяИнтервалыУлучшенная("[-2; 3]", "[3; 5]"); // Истина

// Пример 3: [1; 5] и [3; 7] - пересекаются в интервале [3; 5]
Результат3 = ПересекаютсяИнтервалыУлучшенная("[1; 5]", "[3; 7]"); // Истина

Ключевые моменты

  1. Открытая граница — значение не входит в интервал
  2. Закрытая граница — значение входит в интервал
  3. Граничные точки — требуют особой проверки типов границ
  4. Парсинг — критически важен для корректной работы функции