I am running through some practice problems on CodeWars right now and have stumbled upon an issue that I cannot seem to figure out. The problem is straightforward and simple enough:
My function should take a string input, and return the first character that is not repeated anywhere in the string.
For example, if given the input 'stress', the function should return 't', since the letter t only occurs once in the string, and occurs first in the string.
As an added challenge, upper- and lowercase letters are considered the same character, but the function should return the correct case for the initial letter. For example, the input 'sTreSS' should return 'T'.
If a string contains all repeating characters, it should return an empty string ("").
My code is as follows:
const firstNonRepeatingLetter = (string) => {
const letters = {};
// Object that I am assigning key/value pairs to based on the number of occurrences of each letter
string.split('')
.forEach(letter => {
letter = letter.toLowerCase();
if (letters[letter] !== undefined) letters[letter] ;
if (letters[letter] === undefined) letters[letter] = 1;
});
for (let key in letters) {
let val = letters[key];
// Iterate through object and upon finding the first value of 1, evaluate the casing of the key
if (val === 1) {
string.split('')
.forEach(letter => {
// *line16* If the letter in the string is the same as the corresponding key in uppercase, return letter
if (key.toUpperCase() === letter) return letter;
});
// Otherwise, return the key as is
return key;
};
};
return '';
};
This passes all tests except for the 'sTreSS' test. I have ran through the process with the debugger, and ironically, the *if conditional on line 16 displays a local Return value: 'T'
when reaching this point. However, the forEach continues to iterate and I end up with a return value of 't', which is the next return statement in my block.
I am confounded by this and would appreciate any insight into what is causing the issue.
CodePudding user response:
You could instead use Array.find.
if (val === 1) {
const findIt = string.split('').find(letter => key.toUpperCase() === letter);
return findIt || key; // if findIt is undefined (not found), return key
};
CodePudding user response:
There is no way to stop or break a forEach() loop other than by throwing an exception. If you need such behavior, the forEach() method is the wrong tool.
Early termination may be accomplished with:
- A simple for loop
- A for...of / for...in loops
- Array.prototype.every()
- Array.prototype.some()
- Array.prototype.find()
- Array.prototype.findIndex()
Array methods: every(), some(), find(), and findIndex() test the array elements with a predicate returning a truthy value to determine if further iteration is required.
As an alternative, you can use findIndex
:
const findIndex = string.split('').findIndex(letter => key.toUpperCase() === letter);
return findIndex != -1
? string.split[findIndex ]
|| key;
But find()
is neater :)