Help with this recursive function

I need to create a recursive function to loop an array for a certain number. if the array length is smaller then run the function again until the loop counter is equal to the required max loop number.
I wrote this, but it is looping all array again:

    let counter  = 0
    let words    = 'ABC'
    let maxLoop  = 5
    let bigArray = []

    function go () {
        let wordsArray = words.split('')
        for (let i = 0; i < wordsArray.length; i++) {
            counter++
            bigArray.push(wordsArray[i])
        }
        if (counter < maxLoop && maxLoop >= counter) {
            bigArray.map(num => num + counter)
            go()
        }
    }

The result is: [“A”, “B”, “C”, “A”, “B”, “C”]
and it should be: [“A”, “B”, “C”, “A”, “B”]

How to solve it?

Ok first off you don’t need the second condition && ... they are pretty much doing the same thing
(counter < maxLoop && maxLoop >= counter)

e.g. if x === 2 && 2 === x

if counter < maxLoop will suffice

Strings have a length property e.g.
console.log('abc'.length) // 3

You can access individual characters just like an array by index e.g.
console.log('abc'[1]) // b

So no need to split your letters (not words) and make a wordsArray

I don’t like that you function mutates(changes) variables and properties outside of the function and I think it is best if your function returns something useful. However keeping in line with your code.

Something like this possibly?

let counter = 0
const letters = 'ABC'
const maxLoop = 5
const bigArray = []

function go () {
  for (let i = 0, len = letters.length; i < len && counter < maxLoop; i++) {
    bigArray.push(letters[i]) // or bigArray[counter] = letters[i]
    counter++
  }

  if (counter < maxLoop) go()
}

go()
console.log(bigArray)

Of course you could just use the modulus operator (%) instead

function makeLetters (word, maxLoop) {
  const bigArray = []
  const wordLen = word.length

  for (let i = 0; i < maxLoop; i++) {
    // use % modulus to return the remainder
    // e.g. 1 % 3 = 1, 3 % 3 = 0, 4 % 3 = 1
    bigArray[i] = word[i % wordLen]
  }

  return bigArray
}

console.log(makeLetters('ABC', 5))
4 Likes

Thanks a lot. The purpose of splitting is to convert the letters to ASCII number, then compare if there are 2 numbers in a row are the same, if yes, then add the counter number.

    let counter    = 0
    const letters  = 'ABCCKK'
    const maxLoop  = 10
    const bigArray = []

    function go () {
        for (let i = 0, len = letters.length; i < len && counter < maxLoop; i++) {
            if (i > 0 && letters[i].charCodeAt(0) === letters[i - 1].charCodeAt(0)) {
                bigArray.push(letters[i].charCodeAt(0) + counter)
            }else {
                bigArray.push(letters[i].charCodeAt(0)) // or bigArray[counter] = letters[i]
            }
            counter++
        }

        if (counter < maxLoop) go()
    }

    go()
    console.log(bigArray)

The problem here if the counter is zero then ‘charCodeAt’ will return an error.

it is working now, the error was in this line ‘i < 0’ … but is there better way?

Well done.

As mentioned in another thread I am kind of out of action for a bit, so please feel free to chime in, anyone? :slight_smile:

/me looks around - everyone’s taken one step back.

I’ll see what can be done by cleaning up the code and looking for improvements.

1 Like

Nice one I love it, I got some useful inputs here. Thanks!

1 Like

This doesn’t really require recursion.

I haven’t tested this code, but off the top of my head, something like…

const letters = "ANCCKK".split("").map(x => x.charCodeAt(0));
for(l = 0; l < maxLoop; l++) {
   letters.map(x,i,a => (i === 0) ? x : x+l*(x === a[i-1]))
}

EDIT: Oh wait, you were increasing your counter on every subloop. So it’d be x+(l*a.length+i)*(x === a[i-1])

2 Likes

Side question: What do you expect your function to do if I put in “ZZ”? Arbitrarily adding values to ASCII codes can produce some very odd strings at the end… What would happen if my string were 255 characters long, and ended in ZZ? What value comes out the other end of your code?

I would like to tag on to that with a question.

What is the intended purpose of this code? Is it just to practice some recursion? Is it a teaching exercise? Is it an employment interview challenge? Is it actually going to be used in the real world for some as-yet unstated purpose?

Oops - more than one question, but further details would be nice to know.

1 Like

since you asked the purpose of the code … for my self only, I’m trying to create code to generate a one time pad (OTP) to use it for Vernam Cipher

The problem with OTP, that the message & the OTP should the same length, which is hard to achieve this and remember it.
So, the idea to generate the OTP from a few words that easy to remember it, the code will create a unique OTP based on mod 26 with another simple math equation.
Based on that, for example, if you the words are: cat, dog, AAA
The code will convert them to ASCII, take the weight of the total (length/number of chars), and it will use to increase the ASCII number if the previous number is equal to the current.
I wrote a long function before I make simple, but I got a problem, the message should not be readable if one char in the OTP is wrong, now I’m trying to figure out from the above code how to do it.

The idea may I start with is to take mod 26 of the total ASCII value and use it with another mod:
mod(totalMode+ASCII, 26), so if one char is changed the OTP will be changed, what do you think, is it the right way?

Below is my old function to generate the OTP …

generatePad () {
            let otpString       = this.otpOne + this.otpTwo + this.otpThree + this.otpFour + this.otpFive;
            let otpStringArray  = otpString.split('').map(char => char.charCodeAt(0));
            let otpStringSorted = otpStringArray.sort();
            let median          = this.median(otpStringSorted);

            const startTime = performance.now()

            let newStr = [];
            for (let e = 0; e < otpStringSorted.length; e++) {
                if (e + 1 !== otpStringSorted.length)
                    newStr.push(Math.ceil((otpStringSorted[e] + otpStringSorted[e + 1])) + 1)
            }
            otpStringSorted = [...newStr].sort();

            let left = [], right = [], odd = [], even = [];
            odd.push(otpStringSorted.filter(num => Math.abs(num) % 2 === 1));
            even.push(otpStringSorted.filter(num => Math.abs(num) % 2 === 0));
            right.push(otpStringSorted.filter(num => Math.abs(num) > median));
            left.push(otpStringSorted.filter(num => Math.abs(num) < median));
            let chunksOne          = this.makeChunks(otpStringSorted, 2);
            let chunksTwo          = this.makeChunks(otpStringSorted, 3);
            let chunksThree        = this.makeChunks(otpStringSorted, 4);
            let chunksFour         = this.makeChunks(odd.concat(right).flat(), 2);
            let chunksFive         = this.makeChunks(even.concat(left).flat(), 2);
            let otpStringSortedRev = Array.from(otpStringSorted).reverse();
            let stringsArraysV1    = [
                ...odd.flat(),
                ...left.flat(),
                ...even.flat(),
                ...right.flat(),
                ...chunksOne.flat(),
                ...chunksTwo.flat(),
                ...chunksThree.flat(),
                ...chunksFour.flat(),
                ...chunksFive.flat(),
                ...otpStringSortedRev.flat()];
            let stringsArraysV2    = [
                ...even.flat(),
                ...right.flat(),
                ...odd.flat(),
                ...even.flat(),
                ...chunksFive.flat(),
                ...chunksFour.flat(),
                ...chunksThree.flat(),
                ...chunksTwo.flat(),
                ...chunksOne.flat(),
                ...otpStringSortedRev.flat()];
            let stringsArraysV3    = stringsArraysV1.filter(num => Math.abs(num) % 2 === 1 ? num / 2 : num)
            let stringsArraysV4    = stringsArraysV2.filter(num => Math.abs(num) % 2 === 1 ? num / 2 : num)
            let stringsArraysAll   = [
                ...stringsArraysV1,
                ...stringsArraysV2,
                ...stringsArraysV3,
                ...stringsArraysV4,
                ...this.swapArrayEls(otpStringSorted),
                ...this.swapArrayEls(left),
                ...this.swapArrayEls(otpStringSortedRev),
                ...this.swapArrayEls(even),
                ...this.swapArrayEls(stringsArraysV1),
                ...this.swapArrayEls(odd),
                ...this.swapArrayEls(stringsArraysV2),
                ...this.swapArrayEls(right),
                ...this.swapArrayEls(stringsArraysV3),
                ...this.swapArrayEls(otpStringSorted),
                ...this.swapArrayEls(stringsArraysV4),
            ];
            let firstArray         = Array.from(this.swapArrayEls(stringsArraysAll));
            let secondArray        = Array.from(this.swapArrayEls(otpStringSortedRev));
            let thirdArray         = Array.from(this.swapArrayEls(stringsArraysV1));
            let fourthArray        = Array.from(this.swapArrayEls(stringsArraysV2));
            let fifthArray         = Array.from(this.swapArrayEls(stringsArraysV3));
            this.stringPad         = [
                ...firstArray,
                ...secondArray,
                ...thirdArray,
                ...fourthArray,
                ...fifthArray,
                ...this.makeChunks(firstArray, 2),
                ...this.makeChunks(secondArray, 2),
                ...this.makeChunks(thirdArray, 2),
                ...this.makeChunks(fourthArray, 2),
                ...this.makeChunks(fifthArray, 2),
                ...this.swapArrayElsShort(firstArray),
                ...this.swapArrayElsShort(secondArray),
                ...this.swapArrayElsShort(thirdArray),
                ...this.swapArrayElsShort(fourthArray),
                ...this.swapArrayElsShort(fifthArray),
                ...stringsArraysAll];

            const stopTime = performance.now();
            const duration = (stopTime - startTime) / 1000;

            //x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
            // console.log('test', this.stringPad.length / otpString.length)
            //this.padSize = this.stringPad.length.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
            // this.padSize = this.stringPad.length;


            console.groupCollapsed('PAD Generation');
            console.info('PAD Size', this.stringPad);
            console.info('PAD LENGTH', this.stringPad.length);
            console.info('String Time', duration.toLocaleString('en-US') + 'ms');
            console.groupEnd()
        }
1 Like