Extract the desired numbers from the array in the object



I have an object with array values , and I want to extract my desired numbers from that with this condition :

First , I should check that if numbers in array are ascending or descending, so if they were one of them, return them , but if they were not check this:

If the numbers in the array are starting from a specific number like 1 or 2 or 1000 and one unit is added each time with a special pattern,like 1, 0, 0, 2, 0, 0, 3, 0, 0 or 1000, 10, 1001, 20, 1002, 30,.. the numbers between them (they also should be consecutive) can be extracted, for example: If this was the array

[1, 300, 400, 2, 500, 650, 3, 800, 1130],

the output should be this: [300, 400, 500, 650, 800, 1130],

Or if this was the array:

[4, 60, 5, 50, 6, 40.3],

the output should be this: [60, 50, 40.3]

So it doesn’t matter how much elements are in between 1 and 2 in first array or 4 and 5 in second array, but if there were 3 elements between 1 and 2 , Also 3 elements should be between 3 and 4 , and the numbers between them should be consecutive , (In first array as you can see numbers are ascending and in second array numbers are descending. So here we want consecutive numbers between numbers that added 1 unit every time).

And if none of the conditions were met, just return an empty array for every Object.value that doesn’t conditions.

More details :

This is my code and I tried to write the code but I don’t know how to find numbers and push consecutive number elements between them and push to new array,I can only check ascending or descending numbers in an array.

const numbers : {
   number1 : [1, 300,400,2,500,900,3,1000,1100,4,1200,1800], 
   number2 : [0, 1.1, 1, 1.2, 2, 1.3, 3, 1.4],
   number3 : [2, 1000, 3, 980, 4, 700, 5,100, 6, 10],
   number4 : [1000, 1001, 1001.3, 1003, 1014],
   number5 : [34, 76, 0, 50, 0.5, 1010, 0.5],
};

//The output I want : 
// {
//    number1 : [300, 400, 500,900,1000,1100,1200,1800], 
//    number2 : [1.1, 1.2, 1.3, 1.4],
//    number3 : [1000, 980, 700, 100, 10],
//    number4 : [1000, 1001, 1001.3, 1003, 1014],
//    number5 : []
// };

const res = {}
for(var i=0, i < Object.values(numbers).length, i++){
  el = Object.values(number)[i];
  if (consecutive(el) == true) {
         res[Object.keys(numbers)[i]] = el;
  }else{
        //check and find numbers that added one unit and extract numbers between them.
  }
}

//This function check if numbers are consecutive or not, for consecutive numbers in array returns the last element and for non-consecutive numbers returns false.
const consecutive = (param) => {
  let res = param.reduce((prev , next) => {
    if(prev < next) {
      if(prev == false) {
        return prev
      }
      return next;
    }else{
      return false;
    }
  })
  return (typeof res == 'number') 
}

So How can I find the numbers added one unit every time and delete them and push them to new array?

Answer

I would suggest a separate function that checks whether an input array is monotone (either all descending, or all ascending).

In case the input is not monotone, it requires a bit of tedious checking, but the idea is to find the position of the starting value + 1. If found, then you know the gap size and can verify the rest of this sequence by jumping through the array by that interval, and you can also collect the intermediate values. If the jump exercise confirmed that the “delimiter” values are all incrementing with 1, then you can check that the collected intermediate values are monotone using the function mentioned in the first paragraph.

There is a boundary case where the second value appears multiple times, and more than one possibility exists. This is the case with [1,0,2,2,3,4]. It can be broken up into either of these:

  • [1,[0],2,[2],3,[4]] => [0,2,4], or
  • [1,[0,2],2,[3,4]] => [0,2,3,4]

The solution below will in such case favor the first solution. It is easy to change that behaviour.

Code:

function monotone(numbers) { // Return argument when it is all increasing/decreasing, else []
    if (numbers.length < 2) return numbers;
    let inc = numbers[1] - numbers[0];
    for (let i = 2; i < numbers.length; i++) {
        if ((numbers[i] - numbers[i-1]) * inc <= 0) return []; 
    }
    return numbers;
}

function extract(numbers) {
    let test = monotone(numbers);
    // We're done when input is all ascending or descending
    if (test.length == numbers.length) return numbers; 
    let start = numbers[0];
    let gap = numbers.indexOf(start + 1);
    while (gap > 0) {
        if (numbers.length % gap == 0) {
            collect = [];
            for (let j = 0, expect = start; j < numbers.length && numbers[j] === expect; j += gap, expect++) {
                collect.push(...numbers.slice(j + 1, j + gap));
            }
            if (collect.length === numbers.length - (numbers.length / gap)) {
                collect = monotone(collect);
                if (collect.length) return collect;
            }
        }
        gap = numbers.indexOf(start + 1, gap + 1);
    }
    return monotone(numbers);
}

const numbers = {
   number1 : [1, 300,400,2,500,900,3,1000,1100,4,1200,1800], 
   number2 : [0, 1.1, 1, 1.2, 2, 1.3, 3, 1.4],
   number3 : [2, 1000, 3, 980, 4, 700, 5,100, 6, 10],
   number4 : [1000, 1001, 1001.3, 1003, 1014],
   number5 : [34, 76, 0, 50, 0.5, 1010, 0.5],
   trincot:  [1,0,2,2,3,4] 
};

const result = Object.fromEntries(
    Object.entries(numbers).map(([key, numbers]) => [key, extract(numbers)])
);

console.log(result);


Source: stackoverflow