У меня есть список объектов-отрезков следующего вида:
public Class Line
{
public int Type;
public float From;
public float To;
}
Поле type может быть 2 или 3, если 2, то нужно объединить отрезки, если 3 то из всех предыдущих отрезков вычесть текущий.
Например, пусть список с такими элементами:
Порядок элементов в списке важен.
В результирующем списке мне необходимо получить следующий список:
т.е. вот какой смысл: я бегу в цикле по исходному списку, определяю общие точки между текущим элементом и элементами результирующего списка. Если результирующий список пуст, то туда добавляю текущий элемент, если там есть элементы, то мне нужно в зависимости от типа отрезка объединить его со всеми, что есть в результирующем списке или вычесть из всех элементов результирующего списка текущий элемент.
Мне удобнее представлять исходный и результирующий списки отрезков в таком виде:
за сплошной вертикальной чертой, я формирую итоговый вариант
Подкиньте идею, для решения данной задачи. Любая помощь приветствуется.
Трансформируем данные в (значение-дельта). Значение - это число из колонки "от" или "до" (всё валим в кучу, короче), а дельта - для начала типа 2 это +1, для конца типа 2 это -1, для начала типа 3 это -N, где N больше количества записей типа 2, для конца типа 3 соответственно +N. Полученную кучу сортируем по Значению, считаем нарастающую сумму по Дельте. Если сумма стала больше нуля - начинаем интервал, если ноль или меньше - заканчиваем.
Всё.
Применительно к показанным исходным данным это получится
Значение Дельта Сумма
0 1 1
3 -5 -4
5 1 -3
7 -1 -4
9 -1 -5
10 1 -4
11 5 1
12 -1 0
15 1 1
17 -1 0
Соответственно интервалы 0-3, 11-12 и 15-17.
Если порядок важен, то обрабатываем последовательно - сперва две записи, затем итог (ему присваивается тип 2) плюс третья, итог плюс четвёртая... для исходных данных это будет:
Первые две:
0 1 1
5 1 2
7 -1 1
9 -1 0
Итого - (0-9).
Итог плюс третья:
0 1 1
9 -1 0
10 1 1
12 -1 0
Итого - (0-9), (10-12).
Итог плюс четвёртая:
0 1 1
3 -5 -4
9 -1 -5
10 1 -4
11 5 1
12 -1 0
Итого - (0-3), (11-12)
Добавляем пятую:
0 1 1
3 -1 0
11 1 1
12 -1 0
15 1 1
17 -1 0
Результат - (0-3), (11-12), (15-17)
Способ, предложенный @Akina оптимален и решает задачу, но т.к. количество значений относительно небольшое предлагаю как альтернативу подход «в лоб», который возможно будет легче читать/тестировать.
Подготовка:
Для подготовки нужно создать вспомогательные методы в Line
:
bool DoesIntrsect(Line other)
Line Join(Line other)
List<Line> Subtract(Line other)
Первые два достаточно тривиальны. Для третьего нужно будет рассмотреть несколько случаев:
Случай 1 │ Случай 2 │ Случай 3 │ Случай 4 │ Случай 5
---- │ ----- │ ----- │ ----------- │ ----
———— │ ———— │ ————— │ —————— │ —————————
В первых трех случаях возвращается один отрезок, в четвертом — два, в пятом — ни одного.
Алгоритм:
Основная идея: создать список отрезков, который на каждом шаге содержит текущий результат и для которого выполняются условия:
Сначала список пустой. Пошагово обрабатываем отрезки. Для каждого шага:
Subtract
добавляем в список;То, что список отсортирован потенциально позволит сократить пробег по списку. Возможно, на текущих объемах это и не требуется.
NB: Рассмотрите особенно внимательно к случаям, когда отрезки касаются (они должны объединяться)/совпадают (результат вычитания должен быть пустым). В крайних точках легко допустить ошибку.
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
ЗдравствуйтеПомогите пожалуйста, существует на странице форма, которая принимает файл
Как сделать поиск через TextBox по RichTextBox? Есть пример кода с англоязычного форумаПодскажите как это можно использовать или же сделать