skip to Main Content

Im trying to solve this kata:
https://www.codewars.com/kata/63f96036b15a210058300ca9/train/javascript

"In this kata, you need to write a function that takes a string and a letter as input and then returns the index of the second occurrence of that letter in the string. If there is no such letter in the string, then the function should return -1. If the letter occurs only once in the string, then -1 should also be returned."

Im useing ASCII code to to convert letters in order to distinguish capital and small letters. But i get problem with random tests. I have no idea what im doing wrong…

  1. Im converting array and the symbol into ASCII code.
  2. Im using if statement: If the symbol isn’t in the array I return -1.
  3. If the symbol first and last index don’t match I convert the first one into ‘=’ and return the second occurrence.
  4. In the rest of the cases I return the first and only occurrence.
const secondSymbol = (str, symbol) => {
  console.log(str, symbol);
  let symbolAscii = symbol.charCodeAt(0);
  const strArrAscii = str.split('').map(ele => ele.charCodeAt());
  if (strArrAscii.indexOf(symbolAscii) === -1) return -1;
  else if ((strArrAscii.indexOf(symbolAscii) !== strArrAscii.lastIndexOf(symbolAscii))) 
    {
     strArrAscii[strArrAscii.indexOf(symbolAscii)] = '=';
     return strArrAscii.indexOf(symbolAscii);
    }
  else return strArrAscii.indexOf(symbolAscii);
}

secondSymbol('CQigLHAAxTuCezwqbqMeGOnECbSyLdNfYUxqkLAUvPZzSFbhTfwSVGWzuqvotdOjRxksLRIAQQvogvUmYAr p
fYSbpOOLcxuzD', 'L');

6

Answers


  1. Chosen as BEST ANSWER

    OMG... i didn't read the whole Instruction: "If the letter occurs only once in the string, then -1 should also be returned." I also learned that indexOf() distinguishes capital and small letters... I guess the lesson is don't do katas when You have high fewer because You will make silly mistakes xD


  2. Shouldn’t the last else return -1?

    Your method is quite painful. Why not try this approach:

    Extract the first character. No need to convert the characters into numbers.

    Look for the index of that character in str.slice(1). This will look in the remainder of str.

    Obviously you must add 1 to the result if it is not -1.

    Login or Signup to reply.
  3. I think you are overcomplicating things a bit.

    Compare with this, working solution:

    const secondOccurence = (str, letter) => [...str]
      .map((x, i) => x === letter && i)
      .filter(x => x !== false)[1] || -1;
    
    // Test
    console.log(secondOccurence('abacda', 'a')); // => 2
    console.log(secondOccurence('abacda', 'z')); // => -1
    console.log(secondOccurence('abacda', 'b')); // => -1
    

    Explanation:

    1. Convert the string to an array of letters, using a spread.
    2. Use map go through each letter and store the index of each hit and false for none-hits. (Map creates a new array with the same number of elements as the original.)
    3. Remove all the false elements from the string using filter. Now you have indexes of all hits. Return the index of the second hit or -1 if that does not exist.
    Login or Signup to reply.
  4. The problem is in your final else block. This deals with the case when there is only one occurrence of the letter. The challenge explains that you should return -1 in that case, yet you return the index of that character.

    So change that final else from this:

    else return strArrAscii.indexOf(symbolAscii);
    

    to this:

    else return -1;
    

    Remarks

    • There is no need to convert characters to their numerical code. In JavaScript you can compare characters without any need of conversion.

    • There is no need to create an array from your string (using split("")). You can get the index of a character by directly calling indexOf on the string.

    • You can make use of the second argument of the indexOf method, which is useful to find the second occurrence.

    Like this:

    const secondSymbol = (str, symbol) => {
      let i = str.indexOf(symbol);
      if (i >= 0) i = str.indexOf(symbol, i + 1);
      return i;
    }
    
    Login or Signup to reply.
  5. OK, so here’s my code:

    const secondSymbol = (str, sub) => str.indexOf(sub, str.indexOf(sub)+1);
    
    console.log(secondSymbol('CQigLHAAxTuCezwqbqMeGOnECbSyLdNfYUxqkLAUvPZzSFbhTfwSVGWzuqvotdOjRxksLRIAQQvogvUmYAr pfYSbpOOLcxuzD', 'L'));
    

    Works well, and is short. 🙂

    Login or Signup to reply.
  6. Short one: Use matchAll that will automatically convert the string char into a regex with a ‘g’ flag (so we don’t need to do it), then we spread the iterator returned from matchAll into an array. Each item is an object that (among other things) contains the index of where the match was found. Return the index of the second item, or if no second item, return -1:

    const index2 = (str,char) => [...str.matchAll(char)][1]?.index || -1;
    

    See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/matchAll

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search