1

So I'm working on this codility coding challenge and I cannot get the code to work for all inputs, particularly large ones. The rules for this are here.

To summarize, I need each word in the string to be tested for: alpha-numeric characters only, even number of letters, and odd number of digits.

For the sample input - "test 5 a0A pass007 ?xy1", this solution effectively ignores "test" (it has an even number of digits, 0 digits) and "?xy1" (special character, ?). From the leftover options, it chooses pass007 as the longest word and returns 7 (length of word).

I start by splitting the string into separate words and then generating if statements to check if each word in my new array meets the requirements, isAlpha, isAlphaEven (remainder 0 for even # of letters), isNumeric (remainder 1 for odd numbers).

Any idea what I am doing wrong? Thanks much! :)

 // you can write to stdout for debugging purposes, 
 // e.g. console.log('this is a debug message');

function solution(S) {
// write your code in JavaScript (Node.js 8.9.4)
// you can write to stdout for debugging purposes, 
// e.g. console.log('this is a debug message');
// write your code in JavaScript (Node.js 8.9.4)
var words = S.split(" "); 
var isAlpha = /^[0-9a-zA-z]*$/; 
var isAlphaEven = /^[a-zA-Z]/;
var isNumeric = /^[0-9]/; 
var maxLength = -1;

for(var i = 0; i <= words.length - 1; i++) { 
    if(words[i].match(isAlpha) 
    && words[i].replace(isAlphaEven, '').length % 2 == 0
    && words[i].replace(isNumeric, '').length % 2 == 1
    || words[i].match(isNumeric)
    ) {
        maxLength = Math.max(maxLength, words[i].length);
        //console.log(words[i], maxLength);
    }
}

 return maxLength; 
}
4
  • 1
    isAlphaEven and isNumeric only match the first character of the string. Commented Sep 3, 2019 at 6:25
  • When you replace isAlphaEven with an empty string, you're getting the length of all the characters that don't match it, not the number of alpha characters. Commented Sep 3, 2019 at 6:26
  • You can't really use regular expression to check that the length is a multiple of two, merely that there is at least two. Commented Sep 3, 2019 at 6:27
  • You can get the number of alpha characters with alpha = words[i].match(/[a-z]/gi); numAlpha = alpha ? alpha.length : 0;. The variable is needed because match() returns null if there are no matches rather than an empty array. Commented Sep 3, 2019 at 6:30

2 Answers 2

4

One problem is that the patterns

var isAlphaEven = /^[a-zA-Z]/;
var isNumeric = /^[0-9]/; 

can only match characters at the start of the string: ^ anchors to the beginning. It also isn't a global match, so it'll only replace one character. Another problem is that you're replacing the matches with the empty string, rather than testing the number of matches. To test the number of matches, use .match instead, with the global flag, and check the length of the resulting array (or null if there are no matches):

function solution(S) {
  // write your code in JavaScript (Node.js 8.9.4)
  // you can write to stdout for debugging purposes, 
  // e.g. console.log('this is a debug message');
  // write your code in JavaScript (Node.js 8.9.4)
  var words = S.split(" ");
  var allAlphaNumeric = /^[\da-z]*$/i;
  var alpha = /[a-z]/gi;
  var numeric = /\d/g;
  var maxLength = -1;

  for (var i = 0; i <= words.length - 1; i++) {
    if (words[i].match(allAlphaNumeric) &&
      (words[i].match(alpha) || []).length % 2 == 0 &&
      (words[i].match(numeric) || []).length % 2 == 1
    ) {
      maxLength = Math.max(maxLength, words[i].length);
    }
  }

  return maxLength;
}

console.log(solution("test 5 a0A pass007 ?xy1"));

Note that you can use the case-insensitive flag instead of repeating a-zA-Z, and you can use \d instead of [0-9] if you wish.

While you could use .replace to figure out the number of matches, it'd be convoluted: you'd have to replace everything that doesn't match with the empty string, which would make the code's intent somewhat confusing.

Sign up to request clarification or add additional context in comments.

Comments

0

You already have the answer why your approach didn't work as expected.
So I thought I could add a slightly different approach with multiple .filter() steps

function findLongestWord(input) {
  const isAlphaNumericOnly = /^[a-z0-9]+$/i;
  const numbersOnly = /\d/g;
  const alphaOnly = /[a-z]/gi;
  
  const validWords = input.split(/\s/)
                          .filter(word => isAlphaNumericOnly.test(word))
                          .filter(word => (word.match(numbersOnly) || []).length % 2 === 1)
                          .filter(word => (word.match(alphaOnly) || []).length % 2 === 0)
                          .sort((a, b) => b.length - a.length);
                           
  return {
    word:   validWords[0],
    length: validWords[0] ? validWords[0].length : -1
  };
}


console.log(findLongestWord("test 5 a0A pass007 ?xy1"));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.