H
H
HealSpirit2022-01-26 13:33:53
JavaScript
HealSpirit, 2022-01-26 13:33:53

How to get the remaining range after "cutting" parts out of that range?

Hello. There is a scale from 0 to 86400 (in fact, these are seconds received from 0 to 24h).
There is some range on this scale, for example [32400, 54000] (9-15 hours).
61f11b9b9f65e798480277.png
This range is the only one.

Ranges of the same kind are “thrown” to it from the outside, which “cut out” some parts of it as well.
61f11d79c90a9892266820.png
Someone may not hit at all, someone may hit completely, some range may completely overlap the target range, and nothing will remain of the target range (there are test cases at the end)
According to the result, 2 pieces will remain from the target range:
61f11ed693878784646180.png
This is the result which the function should return -
I wrote a function that works 90% of the time. But 1 case turns the function into incorrectly working.

function

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;
};


tests

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

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

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

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

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

    expect(getSpaceRanges(bounds, )).toEqual([bounds]);
    expect(getSpaceRanges(bounds, )).toEqual([bounds]);
    expect(getSpaceRanges(bounds, )).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();
    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],
    ]);
  });


The falling test is commented out.
61f12254d23c5626569344.png
Returns [], but should

Any thoughts? Thanks

Answer the question

In order to leave comments, you need to log in

1 answer(s)
A
Alexandroppolus, 2022-01-26
@HealSpirit

const bounds: TRange = [32400, 54000];

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

on the first iteration, the condition (intersectionStart > lastBoundsBlockStart && intersectionEnd < lastBoundsBlockEnd) is triggered , with cutting and adding the block [37000, 54000]
on the second iteration, this new block is covered with a cut [36000, 54000], i.e. the first if is triggered, as a result, correctBounds = []; , it returns. Replace correctBounds = []; on correctBounds.pop() should let go.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question