Create dynamic array within certain range values

I am trying to find the best way to generate an array that has the following output:

[135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 275, 276, 277 , 278, 279, 280, 281, 282, 283, 284, 285, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 565, 675, 676, 677, 678, 679, 700, 701, 702, 703, 704, 705 ...

As you can see it has a set of limits from 140 - 280 - 420 - 560 - 700 ( adds 148 to each value) and then there's an interval with minus 5 and plus 5 for each value.

I already tried this approach

scrollFrom =  Array.from(Array(bytesIndexTo).keys()).map(i => 140 + i * 140);

That returns me:

[140, 280, 420, 560, 700, ...

However I also need the plus and minus 5 values intervals...

I also noticed it uses to much resources.

        const prev = [
            [135,136,137,138,139],
            [275,276,277,278,279],
        ];

        const after = [
            [141,142,143,144,145],
            [281,282,283,284,285],
        ];

        for (let i = 0; i < scrollFrom.length; i++) {

            scrollFrom.push( scrollFrom[i] );

        }

The purpose of this array is to have a set of values that will help me to identify a certain scroll position in order to execute a function, the addition of this intervals will help me to figure the scroll position even if the user scrolls fast.

Maybe I could load the values inside a .json and load them ?

What do you think ? thanks in advance

Upvotes: 0

Views: 276

Answers (2)

jfriend00
jfriend00

Reputation: 707218

So, if you all you really want to do is to be able to test if a number is within 5 of a sentinel multiple, then I don't think you really want to be generating a giant array and using .includes(). That would be slow. If you were going to pre-generate values, you should use a Set and then use .has() which should be a lot faster than .includes() for a large set of data.


But, it seems to be that you can just calculate a lot faster without doing any pre-generation at all.

In the code below, we divide by the multiple (140) and then look at the remainder. If the remainder is <=5 or >= 135, then it's within 5 of the multiple, otherwise not. It's really that simple. Since it appears you don't want the numbers 0-5 (around the zero multiple) to be counted as true, we add a special case for those.

// tests to see if a value is within 5 of a multiple of 140
const multiple = 140;
const over = 5;
const below = multiple - over;

function testValue(val) {
    if (val < below) return false;
    const delta = val % multiple;                // divide by multiple, get remainder
    return (delta <= over || delta >= below);  // see if remainder in right range
}

// run some tests on numbers at edges of the interval ranges
[
    0, 1, 
    134, 135, 140, 144, 145, 146,   // around 140
    274, 275, 280, 284, 285, 286,   // around 280
    414, 415, 420, 424, 425, 426,   // around 420
    554, 555, 560, 564, 565, 566    // around 560
].forEach(num => {
    console.log(`${num}: ${testValue(num)}`);
});

Upvotes: 1

CertainPerformance
CertainPerformance

Reputation: 370679

Once you create an array of central values (eg [140, 280, 420, 560, 700]), you can use flatMap to iterate over each item and construct another array of the 5 values below and above it:

const bytesIndexTo = 4;
const result = Array.from(
  { length: bytesIndexTo },
  (_, i) => (i + 1) * 140
)
  .flatMap(num => Array.from(
    { length: 11 },
    (_, j) => num - 5 + j
  ));
console.log(result);

Upvotes: 2

Related Questions