'JS Find the missing letter (alphabet - array)
Write a function that takes an array of consecutive (increasing) letters as input and that returns the missing letter in the array. It will be always exactly one letter be missing. The array will always contain letters in only one case. Example:
["a","b","c","d","f"] -> "e" ["O","Q","R","S"] -> "P"
Why don't my functions work?
function findMissingLetter(array)
{
let alphabetArr = Array.from('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz');
let alphabetSlice = alphabetArr.slice(alphabetArr.indexOf(array[0]), alphabetArr.indexOf(array[array.length - 1]) + 1);
let missingLetter = alphabetSlice.forEach((e, i) => {
if (e !== array[i]) {
return e;
}
});
return missingLetter;
}
function findMissingLetter(array)
{
let alphabetArr = Array.from('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz');
let alphabetSlice = alphabetArr.slice(alphabetArr.indexOf(array[0]), alphabetArr.indexOf(array[array.length - 1]) + 1);
let missingLetter = alphabetSlice.map((e, i) => {
if (e !== array[i]) {
return e;
}
})[0];
return missingLetter;
}
Solution 1:[1]
For searching for one element in an array use for
loop, like this:
for(let i = 0; i < array.length; i++) {
if(array[i] !== alphabetSlice[i])
return alphabetSlice[i];
}
In this approach you will search for first difference between two arrays. And the difference will be your missing letter :)
Why map doesn't work in this example?
map
function takes data and replaces it with "re-arranged" data. This:
alphabetSlice.map((e, i) => {
if (e !== array[i]) {
return e;
}
}); // for your example will create array
will create [undefined, undefined, undefined, undefined, 'e', 'f']
, so the first element is undefined
.
Why the result array has undefined
?
Because you have return
statement in if
. So when the expression in if
is false, you won't return any value, so the value is undefined
.
More about map you can read on mdn.
Solution 2:[2]
Actually just replace forEach
with find
and change what you're returning, and it will do what's needed.
function findMissingLetter(array)
{
let alphabetArr = Array.from('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz');
let alphabetSlice = alphabetArr.slice(alphabetArr.indexOf(array[0]), alphabetArr.indexOf(array[array.length - 1]) + 1);
let missingLetter = alphabetSlice.find((e, i) => e !== array[i]);
return missingLetter;
}
console.log(findMissingLetter(["a","b","c","d","f"]))
console.log(findMissingLetter(["O","Q","R","S"]))
Array.prototype.forEach() executes a provided function once for each array element.
Array.prototype.find() returns the value of the first element in the provided array that satisfies the provided testing function.
Solution 3:[3]
There is no way to return from a forEach
loop before it iterates through each element.
And forEach
always returns undefined
.
You can find the letter with const missingLetter = alphabetSlice.find((e, i) => e !== array[i]);
Solution 4:[4]
- Iterate over the array from
0
tilllength - 1
- At each iteration, get the
UTF-16 code
of the current and next characters usingString#charCodeAt
, which should have a difference of1
if they are after each other (given that they're of the same case) - If the code of the
next
element doesn't equal to the current one + 1, compute the missing character usingString#fromCharCode
on current code + 1
const findMissingLetter = (array = []) => {
for(let i = 0; i < array.length - 1; i++) {
const current = array[i].charCodeAt(), next = array[i+1].charCodeAt();
const expected = current+1;
if(next !== expected) {
return String.fromCharCode(expected);
}
}
}
console.log( findMissingLetter(["a","b","c","d","f"]) );
console.log( findMissingLetter(["O","Q","R","S"]) );
Solution 5:[5]
The answers and comments already described, why it's not working and why you are getting an unexpected result. I just wanna show a different way to solve this.
You can make use of the fact, that the unicode chars are already sorted and increasing the code point of any value by one, will give you the following letter/char/number.
All you have to do is getting the code point from the lowest and the highest value in your array and test if any char inbetween is inside the array you are testing.
Using this method, you can test within any range, if a letter/char/emoji is missing in the passed list.
function missingChars(arr) {
if (Array.isArray(arr)) {
// generate a sorted copy of the array passed as argument
arr = arr.slice().sort();
// length won't be 1 on emojis and so on, so just test for > 0
if (!arr.every(val => (typeof val == 'string' || val instanceof String) && val.length)) {
throw new Error("Every value must be a string with length > 0.");
}
// lowest item will be at pos 0 after sort()
const first = arr[0].codePointAt(0),
// highest item will be at the last position
last = arr[arr.length-1].codePointAt(0),
resultArr = [];
// for every char in between the lowest and the highest
for (let i = first; i < last;i++) {
// create a string using his code point value
const charToTest = String.fromCodePoint(i);
// test if it is inside the array
if (!arr.includes(charToTest)) {
// if not, add it to the result
resultArr.push(charToTest);
}
}
return resultArr;
}
return null;
}
console.log(missingChars(["?", "?"])); // ['?', '?', '?', '?", '?', '?']
console.log(missingChars(["e", "c", "a"])); // ['b', 'd']
console.log(missingChars(["0", "2"])); // ['1']
console.log(missingChars(["a", "b"])); // []
// ascii range
console.log(missingChars(['\u0000', '\u00FF']));
console.log(missingChars(['', 'a'])); // throws error
Solution 6:[6]
Array.forEach
does not return anything - like others already answered. forEach
just performs a (lambda) function on all elements of an array.
You may want to inspect Array.find
, as also noticed by others.
Here's a bit more generic solution (check missing from alfabet or some other given string):
const findFirstMissing = (arr, from) => [...from
.slice(from.indexOf(arr[0]), from.indexOf(arr[arr.length - 1]) + 1) ]
.find((v, i) => v !== arr[i]) || `complete`;
let alfabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
console.log(findFirstMissing(["a", "b", "c", "d", "f"], alfabet));
console.log(findFirstMissing(["O", "Q", "R", "S"], alfabet));
let someRowOfCharacters = `Charlotte`;
console.log(findFirstMissing(`Charltte`.split(``), someRowOfCharacters));
console.log(findFirstMissing(`Charlotte`.split(``), someRowOfCharacters));
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Christopher |
Solution 2 | |
Solution 3 | Nikita Skrebets |
Solution 4 | |
Solution 5 | Christopher |
Solution 6 |