skip to Main Content

The Accumulator Array(Indices) is initialized correctly to an ’empty array’ during creation in a Reduce loop but on pushing values to it , it becomes ‘Undefined’.

Why does this happen ?

var   data        = { 'Number': [1, 2, 3, 4, 5] };
const startNumber = 2;
const endNumber   = 5;

Numbers_filtered_indices = 
  data['Number']
  .reduce((indices, e, i, arr) => {
    console.log( `loop ${i}`         );
    console.log( 'Accumulator Array' );
    console.log( indices             );
    console.log( `e = ${e}`          );
    console.log( `i = ${i}`          );
    console.log( `arr = ${arr}`      );

    if (startNumber <= e && e <= endNumber) {
      indices.push(i);                     // lineno : 27
      return indices
    }
  }, [])

console.log( 'Numbers_filtered_indices' )
console.log( Numbers_filtered_indices   )
.as-console-wrapper { max-height: 100% !important; top: 0; }

3

Answers


  1. The issue in your code arises because the reduce method expects the accumulator to be returned on every iteration. When the condition startNumber <= e && e <= endNumber is not met, the accumulator (indices) is not returned, leading to an undefined value in the subsequent iteration. This causes the error when trying to use push on undefined.

        var data = { 'Number': [1, 2, 3, 4, 5] };  
    const startNumber = 2;  
    const endNumber = 5;  
    Numbers_filtered_indices = data['Number'].reduce((indices, e, i, arr) => {
        console.log(`loop ${i}`);
        console.log('Accumulator Array');
        console.log(indices);
        console.log(`e = ${e}`);
        console.log(`i = ${i}`);
        console.log(`arr = ${arr}`);
    
        if (startNumber <= e && e <= endNumber) {
            indices.push(i);
        }
        
        // Always return the accumulator array
        return indices;
    
    }, []);
    
    console.log('Numbers_filtered_indices');
    console.log(Numbers_filtered_indices);
    
    Login or Signup to reply.
  2. 
    var data = { Number: [1, 2, 3, 4, 5] }
    const startNumber = 2
    const endNumber = 5
    
    const Numbers_filtered_indices = data['Number'].reduce(
      (indices, e, i, arr) => {
        console.log(`loop ${i}`)
        console.log('Accumulator Array')
        console.log(indices)
        console.log(`e = ${e}`)
        console.log(`i = ${i}`)
        console.log(`arr = ${arr}`)
    
        if (startNumber <= e && e <= endNumber) {
          indices.push(i)
          return indices
        } else {
          // must return something
          return indices
        }
      },
      []
    )
    
    
    Login or Signup to reply.
  3. the condition if(startNumber <= e && e <= endNumber) is not always true(ish). When it isn’t, nothing is returned from the lambda for the reducer. The lambda should always return the accumulator, either the supplemented with a new value or its current value. Otherwise you end up pushing to undefined – which will throw a TypeError.

    Furthermore: your code looks a bit convoluted. Here is a simplification:

    const data = {'Number' : [1,2,3,4,5]};
    const startNumber = 2;
    const endNumber = 5;
    
    const numbersFilteredIndexes = data.Number.reduce( (acc, number, i) =>
      startNumber <= number && number <= endNumber ? [...acc, i] : acc, [] );
    
    console.log(`numbersFilteredIndexes: [${numbersFilteredIndexes}]. 
    So: filtered values from data.Number: [${
      data.Number.filter((v, i) => 
        numbersFilteredIndexes.find(ii => ii === i)) }]`);
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search