@HealSpirit

Как получить оставшийся диапазон после «вырезания» частей из этого диапазона?

Всем привет. Имеется шкала от 0 до 86400 (по факту, это секунды полученные от 0 до 24ч).
На этой шкале есть какой-то диапазон, например [32400, 54000] (9-15ч.)
61f11b9b9f65e798480277.png
Этот диапазон - единственный.

К нему извне "докидываются" такого же рода диапазоны, которые "вырезают" и него какие-то части.
61f11d79c90a9892266820.png
Кто-то может вобще не попасть, кто-то попадает целиком, какой-то диапазон может полностью перекрыть целевой, и от целевого диапазона ничего не останется (в конце есть тестовые случаи)
По результату от целевого диапазона останется 2 куска:
61f11ed693878784646180.png
Это тот результат, который должна вернуть функция - [[32400, 34000], [35000, 54000]]
Я написал функцию, которая работает в 90% случаев. Но 1 случай превращает функцию в неправильно работающую.
функция

clone, isEmpty, forEach используется из lodash
type TRange = [number, number];

export const getSpaceRanges = (bounds: TRange, intersections: TRange[]) => {
  const clonedBounds = clone(bounds);
  let correctBounds: TRange[] = [clonedBounds];

  if (isEmpty(intersections)) {
    return correctBounds;
  }

  forEach(intersections, (intersection) => {
    const [intersectionStart, intersectionEnd] = intersection;
    const lastBoundsBlockIndex = correctBounds.length - 1;
    const [lastBoundsBlockStart, lastBoundsBlockEnd] = correctBounds[lastBoundsBlockIndex];

    if (intersectionStart <= lastBoundsBlockStart && intersectionEnd >= lastBoundsBlockEnd) {
      correctBounds = [];

      return false;
    }

    if (intersectionStart <= lastBoundsBlockStart && intersectionEnd <= lastBoundsBlockStart) {
      return;
    }

    if (intersectionStart <= lastBoundsBlockStart && intersectionEnd > lastBoundsBlockStart) {
      correctBounds[lastBoundsBlockIndex][0] = intersectionEnd;

      return;
    }

    if (intersectionStart > lastBoundsBlockStart && intersectionEnd < lastBoundsBlockEnd) {
      const prevLastBoundsBlockEnd = lastBoundsBlockEnd;

      correctBounds[lastBoundsBlockIndex][1] = intersectionStart;
      correctBounds.push([intersectionEnd, prevLastBoundsBlockEnd]);

      return;
    }

    if (
      (intersectionStart < lastBoundsBlockEnd && intersectionEnd > lastBoundsBlockEnd) ||
      (intersectionStart > lastBoundsBlockStart && intersectionEnd === lastBoundsBlockEnd)
    ) {
      correctBounds[lastBoundsBlockIndex][1] = intersectionStart;

      return;
    }

    if (intersectionStart >= lastBoundsBlockEnd) {
      return;
    }
  });

  return correctBounds;
};


тесты

it("Обрезание трека диапазонами", () => {
    const bounds: TRange = [32400, 54000];

    expect(getSpaceRanges(bounds, [])).toEqual([bounds]);

    expect(getSpaceRanges(bounds, [[5400, 10500]])).toEqual([bounds]);
    expect(getSpaceRanges(bounds, [[5400, 32400]])).toEqual([bounds]);
    expect(getSpaceRanges(bounds, [[5400, 52000]])).toEqual([[52000, 54000]]);
    expect(getSpaceRanges(bounds, [[5400, 54000]])).toEqual([]);
    expect(getSpaceRanges(bounds, [[5400, 56000]])).toEqual([]);

    expect(getSpaceRanges(bounds, [[32400, 32400]])).toEqual([bounds]); // Скорее всего, это невозможно
    expect(getSpaceRanges(bounds, [[32400, 52000]])).toEqual([[52000, 54000]]);
    expect(getSpaceRanges(bounds, [[32400, 54000]])).toEqual([]);
    expect(getSpaceRanges(bounds, [[32400, 56000]])).toEqual([]);

    expect(getSpaceRanges(bounds, [[38000, 38000]])).toEqual([
      [32400, 38000],
      [38000, 54000],
    ]); // Скорее всего, это невозможно, но если возможно, продумать
    expect(getSpaceRanges(bounds, [[38000, 52000]])).toEqual([
      [32400, 38000],
      [52000, 54000],
    ]);
    expect(getSpaceRanges(bounds, [[38000, 54000]])).toEqual([[32400, 38000]]);
    expect(getSpaceRanges(bounds, [[38000, 56000]])).toEqual([[32400, 38000]]);

    expect(getSpaceRanges(bounds, [[54000, 54000]])).toEqual([bounds]);
    expect(getSpaceRanges(bounds, [[54000, 56000]])).toEqual([bounds]);
    expect(getSpaceRanges(bounds, [[56000, 58000]])).toEqual([bounds]);

    /** Более сложные случаи */
    expect(
      getSpaceRanges(bounds, [
        [38000, 40000],
        [45000, 52000],
      ])
    ).toEqual([
      [32400, 38000],
      [40000, 45000],
      [52000, 54000],
    ]);
    expect(
      getSpaceRanges(bounds, [
        [33000, 45000],
        [35000, 48000],
        [46000, 52000],
      ])
    ).toEqual([
      [32400, 33000],
      [52000, 54000],
    ]);
    // expect(
    //   getSpaceRanges(bounds, [
    //     [35000, 37000],
    //     [36000, 54000],
    //   ])
    // ).toEqual([[32400, 35000]]);
    expect(
      getSpaceRanges(bounds, [
        [5400, 10500],
        [35000, 37000],
        [56000, 58000],
      ])
    ).toEqual([
      [32400, 35000],
      [37000, 54000],
    ]);
    expect(
      getSpaceRanges(bounds, [
        [5400, 33000],
        [35000, 37000],
        [53000, 58000],
      ])
    ).toEqual([
      [33000, 35000],
      [37000, 53000],
    ]);
  });


Падающий тест закоменчен.
61f12254d23c5626569344.png
Возвращает [], а должен [[32400, 35000]]

Есть какие-то мысли? Спасибо
  • Вопрос задан
  • 62 просмотра
Решения вопроса 1
Alexandroppolus
@Alexandroppolus
кодир
const bounds: TRange = [32400, 54000];

    //   getSpaceRanges(bounds, [
    //     [35000, 37000],
    //     [36000, 54000],
    //   ])


у тебя на первой итерации срабатывает условие (intersectionStart > lastBoundsBlockStart && intersectionEnd < lastBoundsBlockEnd), с разрезанием и добавлением блока [37000, 54000]

на второй итерации этот новый блок накрывается вырезкой [36000, 54000], т.е. срабатывает первый if, как следствие, correctBounds = [];, оно и возвращается. Замени correctBounds = []; на correctBounds.pop(), должно отпустить.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы