skip to Main Content

Given an array, I want to generate its "prefixes", meaning for an array of size N, I want one array containing the first element, an array containing the first two, an array containing the first three, and so on until I get a copy of all N items in the array.

const arr = [1,2,3,4,5]

for (const i in arr) console.log(i, arr.slice(0, i))
// 0, Array []
// 1, Array [ 1 ]
// 2, Array [ 1, 2 ]
// 3, Array(3) [ 1, 2, 3 ]
// 4, Array(4) [ 1, 2, 3, 4 ]

The above is slightly wrong, since at i=0 I want [1], and at i=4 I want [1,2,3,4,5]. So I modified it to use i + 1, which results in completely unexpected behavior:

for (const i in arr) console.log(i, arr.slice(0, i+1))
// 0, Array [ 1 ]
// 1, Array(5) [ 1, 2, 3, 4, 5 ]
// 2, Array(5) [ 1, 2, 3, 4, 5 ]
// 3, Array(5) [ 1, 2, 3, 4, 5 ]
// 4, Array(5) [ 1, 2, 3, 4, 5 ]

I observed this in the JS console in Firefox, as well as Edge.

Why does it apparently jump straight to an array of length 5 on the second iteration? I confirmed that manually calling arr.slice(0, 3) returns [1, 2, 3] as expected, so why does calling it inside the for loop change the behavior?

3

Answers


  1. Chosen as BEST ANSWER

    Doh, apparently by using the for-in construct, the i value is a String. So i+1 is 01, 11, 21, ....

    I guess I'll swap to for(let i=0; i<arr.length; i++)

    Docs for for..in state:

    Receives a string property name on each iteration.


  2. i is considered as a string. when you do i+1, it will append the 1 on each iteration.

    for (const i in arr) console.log(i, i+1, arr.slice(0, i+1))
    // 0 01 [1]
    // 1 11 (5) [1, 2, 3, 4, 5]
    // 2 21 (5) [1, 2, 3, 4, 5]
    // 3 31 (5) [1, 2, 3, 4, 5]
    // 4 41 (5) [1, 2, 3, 4, 5]
    

    Convert i to numeric and try like below

    for (const i in arr) console.log(i, i+1, arr.slice(0, +i+1))
    
    Login or Signup to reply.
  3. Using in operator for arrays isn’t recommended and widely considered as bad code since it iterates properties of an array (they’re rather strings). The big problem with it also when somebody monkeypatches the prototype like Array.prototype.myEach = ... (which is also bad since creates an enumerable property).

    Just use a number index:

    const arr = [1,2,3,4,5]
    
    for(let i = 1; i <= arr.length; i++) console.log(i, JSON.stringify(arr.slice(0, i)))
    

    Another option is to use Array#keys() to iterate the indexes directly (note that this will be slower than the previous for loop since an iterator involved):

    const arr = [1,2,3,4,5]
    
    for(const i of arr.keys()) console.log(i, JSON.stringify(arr.slice(0, i + 1)))
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search