Just wondering if its acceptable to use a for in loop on a string. Not sure if there could be weird results or bad practice but my solution works at least in this example.
Coding practice question. Also, if anyone has a way to improve my solution I'm open to advice.
function firstNonRepeatingLetter(str) {
const lowerStr = str.toLowerCase();
for (let char in lowerStr) {
if (lowerStr.lastIndexOf(lowerStr[char]) === parseInt(char) &&
lowerStr.indexOf(lowerStr[char]) === parseInt(char)) {
return str[char];
}
}
return "";
}
Write a function named first_non_repeating_letter
that takes a string
input, and returns the first character that is not repeated anywhere in the string.
Examples:
firstNonRepeatingLetter('a') => 'a'
firstNonRepeatingLetter('stress') => 't'
firstNonRepeatingLetter('sTreSS') => 'T'
Just wondering if its acceptable to use a for in loop on a string. Not sure if there could be weird results or bad practice but my solution works at least in this example.
Coding practice question. Also, if anyone has a way to improve my solution I'm open to advice.
function firstNonRepeatingLetter(str) {
const lowerStr = str.toLowerCase();
for (let char in lowerStr) {
if (lowerStr.lastIndexOf(lowerStr[char]) === parseInt(char) &&
lowerStr.indexOf(lowerStr[char]) === parseInt(char)) {
return str[char];
}
}
return "";
}
Write a function named first_non_repeating_letter
that takes a string
input, and returns the first character that is not repeated anywhere in the string.
Examples:
firstNonRepeatingLetter('a') => 'a'
firstNonRepeatingLetter('stress') => 't'
firstNonRepeatingLetter('sTreSS') => 'T'
Share
Improve this question
edited Sep 26, 2019 at 21:36
Das_Geek
2,8357 gold badges22 silver badges27 bronze badges
asked Sep 26, 2019 at 20:37
Joe SpinelliJoe Spinelli
1052 silver badges11 bronze badges
1
- Possible duplicate of What's the difference between a string and an array of characters in Javascript? – PM 77-1 Commented Sep 26, 2019 at 20:41
6 Answers
Reset to default 4While your code is working, I suggest to take an index for iterating the characters of a string.
But your approach iterates the string to much by using indexOf
and lastIndexOf
. This could be changed by using a loop storing the last found index of the character.
In another loop, pare the actual index with the stored one for the same character and return if equal.
function firstNonRepeatingLetter(str) {
var lowerStr = str.toLowerCase(),
hash = {},
i;
for (i = 0; i < lowerStr.length; i++)
hash[lowerStr[i]] = i;
for (i = 0; i < lowerStr.length; i++)
if (hash[lowerStr[i]] === i)
return str[i];
return "";
}
console.log(firstNonRepeatingLetter('a')); // a
console.log(firstNonRepeatingLetter('stress')); // t
console.log(firstNonRepeatingLetter('sTreSS')); // T
To answer the question, yes, you can use for..in
with strings. The truth is, in most cases, you shouldn't.
for(i in X)
works this way:
- if X is not an object, convert it to a respective wrapper (a number to a
Number
, a string to aString
) - for each "enumerable property" of X, assign its name to i and run the loop body
So strings are converted to String
objects, and, as you can see in the console, they are just like arrays: they have numeric properties from 0 to length - 1 and each property contains the respective character:
That is, yes, the above logic works just fine with strings.
However, if you only want to iterate a string char-by-char, there's a more direct way to do the same: the for..of
loop.
for(a of X)
picks each element (not property) from X (which can be a string, an array or any "iterable" object) and assigns it to "a". With for..of
, your code can be refactored like this:
function firstNonRepeatingLetter(str) {
const lowerStr = str.toLowerCase();
for (let char of lowerStr) {
if (lowerStr.lastIndexOf(char) === lowerStr.indexOf(char))
return char;
}
return "";
}
An algorithmic approach using javascript maps
:
And yes, it's perfectly fine to use for loops
with strings.
const fn = (str) => {
res = [];
var ch = new Map();
for(var i = 0; i<str.length; i++) {
if(ch.has(str[i])) {
var val = ch.get(str[i])
val += 1
ch.set(str[i],val)
} else {
ch.set(str[i], 1)
}
}
ch.forEach((val, key) => {
if(val == 1) {
res.push(key)
}
})
return res[0]
}
console.log(fn('abcdeabcdef'))
How about using two array ? Firstly, you can make an array using split
and also create reversed array.
const origin = str.split('');
const reverse = [...origin].reverse();
Then, you can use filter
.
const nonRepeats = origin.filter((ele, index) => ele !== reverse[index]);
return nonRepeats[0];
To answer the question in the title, the for..in
statement is intended for iterating enumerable object properties (including members in the prototype chain). While it "works" on iterable types, it is generally advised against using it as a method of iterating array-like structures as it can yield unexpected results when you are typically only looking at numerical indices.
For example, imagine you later polyfill functionality or otherwise modify the String prototype.
String.prototype.polyfill = () => {}
for(const prop in 'abc')
console.log(prop)
Edit: Oh snap. Looks like two of us got there at the same time. I'll also note then that regular expressions are good at solving this kind of problem. regex 101
const firstNonRepeatingLetter = str =>
(str && /(.)(?!.*?\1)/i.exec(str)[0]) || ''
;[
'a',
'stress',
'sTreSS'
]
.forEach(
str => console.log(firstNonRepeatingLetter(str))
)
I think once you resolve the answer on a website where you have found this task it will show you other answers, so you can see some other approaches.
Back to the question - you can convert string to array via .split()
method. Array provides number of useful methods like .filter()
, .map()
etc. that can be used instead of for
loop.