Home > Software engineering >  Converting nested loops into forEach();
Converting nested loops into forEach();

Time:02-13

Im trying to learn forEach() method but i cant find more advanced examples. So i thought about refactoring my Codewars code to learn from it. I dont know know to properly use forEach method in nested loops. Hope You can help me learn from this example :)

6 kyu - Replace With Alphabet Position https://www.codewars.com/kata/546f922b54af40e1e90001da/train/javascript

function alphabetPosition(text) {
    let textToArray = text.replace(/[^a-zA-Z]/gi,'').toUpperCase().split(''); //Eliminate anything thats not a letter 
    const alphabet = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"];
    let pointsHolder = [];                            //empty array for score
    for (let i = 0; i < textToArray.length; i  ){
        for  (let j = 0; j < alphabet.length; j  ) {
            if (textToArray[i] == alphabet[j] ) {     //We check the index of given string letter in alphabet
                pointsHolder.push(j 1)                //give it a score based on place in alphabet( 1 for 0 as 1st index)
            }
        }
    }
    return pointsHolder.join(' ');                    //return scored array as a string with spaces
}

CodePudding user response:

There is really no need to use a nested loop, which is computationally expensive. With that, you also don't have to manually create an A-Z array.

You can easily convert alphabets to any arbitrary number using String.charCodeAt(). a has a character code of 97, b has a character code of 98, and etc... to get a one-based index (a=1, b=2, ...) you jus t need to subtract 96 from the number.

function alphabetPosition(text) {
  const alphabets = text.toLowerCase().replace(/[^a-z]/g, '').split('');
  return alphabets.map(alphabet => alphabet.charCodeAt(0) - 96).join(' ');
}

Alternatively you can also use a for...of loop, but that requires storing the array in yet another variable before returning it:

function alphabetPosition(text) {
  const alphabets = text.toLowerCase().replace(/[^a-z]/g, '');
  
  const codes = [];
  for (const alphabet of alphabets) {
    codes.push(alphabet.charCodeAt() - 96);
  }
  
  return codes.join(' ');
}

CodePudding user response:

(Note: @Terry's solution is still the more efficient solution to your code challenge)

You can replace it in the following way:

function alphabetPosition(text) {
  let textToArray = text.replace(/[^a-zA-Z]/gi, '').toUpperCase().split(''); 
  const alphabet = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"];
  let pointsHolder = []; 
  textToArray.forEach(t2a => {
    alphabet.forEach((a, j) => {
      if (t2a == a) { pointsHolder.push(j   1) }
    })
  })
  return pointsHolder.join(' '); 
}

console.log(alphabetPosition("ABCSTU"))

CodePudding user response:

An alternative to the charCode solution proposed in Terry's answer but which also avoids nested loops is be to create a Map of the characters you want to score against and then access it per character from the passed string.

Keep in mind that strings are iterable without needing to convert to an array.

function alphabetPosition(text) {
  text = text.toUpperCase().replace(/[^A-Z]/gi, '');

  const alphabet = new Map(
    ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
      .map((v, i) => [v, i   1])
  );

  const pointsHolder = [];
  for (const char of text) {
    pointsHolder.push(alphabet.get(char))
  }

  return pointsHolder.join(' ');
}

console.log(alphabetPosition("AB           
  • Related