using reduce to compose an array of cumulative strings

Viewed 682

I want to return something like this ['4', '42','420'] for a given number: 420

I am using reduce to accumulate the number and using the index to concat the number in the index before. First two iterations are working fine, but in the third one I am having trouble thinking how to deal with the result since it is undefined => [ '4', '42', '4,42undefined' ]

Any thoughts?

function createArrayOfTiers(num) {
  const onArray = String(num).split('') 
  onArray.reduce((acc, curr, index) => {
    if (!index) return curr
    const newAcc = [...acc, acc + curr[index -1]]
    
    return newAcc
  },[])

}
createArrayOfTiers(420)

6 Answers

If you want to collect the incremental digits of a number, I think a clearer approach would be to use .map (or Array.from) instead: on each iteration, slice the (stringified) number from index 0 to the current index.

function createArrayOfTiers(num) {
  const strNum = String(num);
  return [...strNum].map((_, i) => strNum.slice(0, i + 1));
}
console.log(createArrayOfTiers(420));

To fix your existing code, you'll want to access the previous element of the accumulator, not the previous element of curr (which doesn't really make sense), multiply it by 10, and add to it the digit being iterated over. Also make sure to return the constructed array:

function createArrayOfTiers(num) {
  const onArray = String(num).split('')
  return onArray.reduce((acc, curr, index) => {
    if (!index) return Number(curr);
    return [...acc, acc[index - 1] * 10 + Number(curr)];
  }, [])
}
console.log(createArrayOfTiers(420));

You have the error because you forgot to take first number in the third iteration. You take acc + curr[index - 1] but forgot about acc + curr[index - 2].

To fix it you can slice numbers from first to current and then join them.

function createArrayOfTiers(num) {
  const onArray = String(num).split("");
  return onArray.reduce((acc, curr, index, arr) => {
    const newAcc = [...acc, arr.slice(0, index + 1).join("")];

    return newAcc;
  }, []);
}
console.log(createArrayOfTiers(420));

Try this:

function createArrayOfTiers(num) {
  const str = String(num);
  const res = str.split('').reduce((acc, curr, index) => {
    acc = [...acc, str.substring(0,index)+curr];
    return acc;
  }, []);
  return res;
}

console.log( createArrayOfTiers(420) );

my way

const createArrayOfTiers = arg =>
        [...String(arg)].reduce((r,c,i)=>[...r, (r[i-1]||'')+c],[])

 
console.log('420 -->' ,JSON.stringify( createArrayOfTiers(420) ));
console.log("'elisa' -->" ,JSON.stringify( createArrayOfTiers('elisa') ));
.as-console-wrapper{max-height:100% !important;top: 0;}

You could map the stringed value by using a closure of a string which stores the value of the last result.

function createArrayOfTiers(num) {
    return Array.from(num.toString(), (s => v => s += +v)(''));
}

console.log(createArrayOfTiers(420));

The reduce aspect ...

function createArrayOfTiers(num) {
    return [...num.toString()].reduce((r, v) => [...r, (r[r.length - 1] || '') + v], []);
}

console.log(createArrayOfTiers(420));

thanks to CertainPerformance in this thread I understood that I was trying to access the index of an inexistent array in curr therefore I needed to access the index of the acc value and came up to this solution using an updated version of my code:

function createArrayOfTiers(num) {
  const onArray = String(num).split('') 
  const reducer = onArray.reduce((acc, curr, index) => {
    if (!index) return [curr]
    const newAcc = [...acc, acc[index -1] + curr]
    return newAcc
  },[])
  return reducer
}

createArrayOfTiers(420)

I also transformed curr to an array because in case of only one digit, should return an array as well.

Thanks to all who gave brilliant ideas!!

Related