Home > Net >  Spot start and end index of values outside specified bounds?
Spot start and end index of values outside specified bounds?

Time:08-25

I have 3 arrays of size n :

let values = [5, 5, 5, 6, 7, 6, 5, 4, 3, 3, 4, 5, 5];
let min_arr = [3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3];
let max_arr = [7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7];
let n = values.length; 

I am trying to spot the indexes of the start and end of the "zones" where min_arr[i] > values[i] or max_arr[i] < values[i].
In the previous arrays the first zone : values[4] = 7 > 6 = max_arr[4] and !(values[5] = 6 > 6 = max_arr[5]) thus start = 4 and end = 5.
In the previous arrays the second zone : values[8] = 3 < 4 = min_arr[8] and values[9] = 3 < 4 = min_arr[9] but !(values[10] = 4 < 3 = min_arr[10]) thus start = 8 and end = 10.
In the previous arrays the expected output would be : [[4, 5], [8, 10]].
Nb: It does not matter if the last end index is greater than n.
Here is my code so far :

let temp = values
  .map((e, i) => min_arr[i] > e || max_arr[i] < e ? i : undefined)
  .filter((e) => e);
console.log(temp);

Output

[4, 8, 9]

My logic here is to first get all the indexes where the value is not in the bounds before removing consecutive values and adding the end value.

let res = [];
let start = temp[0];
for (let i = 0; i < temp.length; i  ) {
  if (i   1 == temp.length) {
    res.push([start, temp[i]   1]);
    break;
  }
  if (temp[i]   1 != temp[i   1]) {
    res.push([start, temp[i]   1]);
    start = temp[i   1];
  }
}
console.log(res);

Output

[[4, 5], [8, 10]]

As a beginner in JavaScript, I find this method crude and I believe that the whole process can be done in a declarative way. How should I proceed ?

Please don't hesitate to edit this question if it lacks clarity.

CodePudding user response:

Your method will work only for 2 consecutive values , try an example with more consecutive values like [[2, 7], [8, 11]] and check your method .

The solution can be the next:

let values = [5, 5, 5, 6, 7, 6, 5, 4, 3, 3, 4, 5, 5];
let min_arr = [3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3];
let max_arr = [7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7];

const result = values
  .map((num, i) => (min_arr[i] > num || max_arr[i] < num ? i : undefined))
  .reduce((previousValue, currentValue, currentIndex, array) => {
    if ((currentValue || currentValue === 0) && !array[currentIndex - 1]) {
      const findNextSibling = array.slice(currentIndex).findIndex(i => !i);
      const finalConsecutiveValue =
        findNextSibling === -1 || findNextSibling === 0
          ? 1
          : findNextSibling   currentIndex;

      previousValue.push([currentValue, finalConsecutiveValue]);
    }

    return previousValue;
  }, []);
    
    console.log('result', result);

CodePudding user response:

Here are not so crude methods, probably they are in declarative way, also with handling some corner-cases. Corner cases i mean in result you are expencting arrays with 2 elements, open index and close index. So if the last element in array is out of bound - still an array with 2 elements will be returned. And at this point im curious about the correct output, probably you have to clarify it a bit. I assumed that indexes shoult be "first index of item that is out of bounds" and "last index of item that is out of bounds", not the "last index 1"

let values = [5, 5, 5, 6, 7, 6, 5, 4, 3, 3, 4, 5, 5];
let min_arr = [3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3];
let max_arr = [7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7];

function getZones(values, predicateFn) {
  const reduced = values.reduce(
    (acc, curr, i) => {
      const isMet = predicateFn(curr, i);

      if (isMet) {
        if (acc._zone) acc._zone[1] = i;
        else acc._zone = [i];
      } else if (acc._zone) {
        // -1 due to current index is ok, previous was not.
        acc._zone[1] = i - 1;
        acc.result.push(acc._zone);
        acc._zone = undefined;
      }
      return acc;
    },
    {
      _zone: undefined,
      result: []
    }
  );

  // Case when zone was opened and not closed.
  // Happens for last item only.
  const { _zone, result } = reduced;
  if (_zone) {
    if (_zone.length === 1) {
      _zone[1] = _zone[0];
    }
    result.push(_zone);
  }

  return result;
}

const res = getZones(values, (curr, i) => curr < min_arr[i] || curr > max_arr[i]);
console.log(JSON.stringify(res));

Test set i checked with:

const testSets = [
  {
    // Original set
    values: [5, 5, 5, 6, 7, 6, 5, 4, 3, 3, 4, 5, 5],
    min_arr: [3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3],
    max_arr: [7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7]
    // [[4,4],[8,9]]
  },
  {
    // with starting and ending outs
    values: [2, 5, 5, 6, 7, 6, 5, 4, 3, 3, 4, 5, 10],
    min_arr: [3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3],
    max_arr: [7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7]
    // [[0,0],[4,4],[8,9],[12,12]]
  },
  {
    // with starting and ending "wave"
    values: [2, 8, 2, 6, 7, 6, 5, 4, 3, 3, 4, 2, 2, 10],
    min_arr: [3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3],
    max_arr: [7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7]
    // [[0,2],[4,4],[8,9],[11,13]]
  },
  {
    // Completely out of bounds
    values: [2, 2, 2, 2, 2, 2, 2, 8, 8, 8, 8, 8, 8, 8],
    min_arr: [3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3],
    max_arr: [7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7]
    // [[0,13]]
  }
];

Also, here is a codesandbox so you can check the correct output and behavior.

Edit modern-architecture-y5786x

  • Related