0

This is the simplest solution I found. It returns true or false for the given string if it contains all letters of the alphabet in it or not.

Here is the code I found:

new Set("A quick brown fox jumps over the lazy dog"
  .toLowerCase()
  .replace(/[^a-z]/gi, "")
  .split("")
).size === 26

Any other simpler form of checking to see if a string contains all of the letters in the alphabet would be helpful.

Thanks!

Andria
  • 4,712
  • 2
  • 22
  • 38
rockey91
  • 142
  • 2
  • 10

7 Answers7

4

You don't need to split

As it would turn out, you don't need to run String#split before passing your string to new Set. The constructor for Set, when passed a string, will, essentially, split it into single characters for you before creating the set.

Example:

new Set('A quick brown fox jumps over the lazy dog'
  .toLowerCase()
  .replace(/[^a-z]/g, '')
).size === 26

This works just as well because something like new Set('test') turns into

Set(3) {"t", "e", "s"}

On a side note, you can see that I've removed the i flag from the regular expression as pointed out by one of the other answers as it is unnecessary due to the .toLowerCase()

Andria
  • 4,712
  • 2
  • 22
  • 38
3

You can avoid the regex and also return early from the function once you have all the letters with something like this. It creates a set of all the letters and removes them as you find them. Once the set is empty you can return. If the loop finishes, you didn't remove everything. This only requires space for the alphabet set and since set operations are constant time, this is O(n) in the worst case.

function allLetters(str){
    let alpha = new Set("abcdefghijklmnopqrstuvwxyz")
    for (let c of str.toLowerCase()){
        alpha.delete(c)
        if (alpha.size == 0) return true
    }
    return false
}

let text = "hello my name if gunther"
let text2 = "The quick brown fox jumps over the lazy dog"

console.log(allLetters(text))
console.log(allLetters(text2))
Mark
  • 90,562
  • 7
  • 108
  • 148
  • `new Set("abcdefghijklmnopqrstuvwxyz".split(''))` will also take some time – Maheer Ali Mar 23 '19 at 07:14
  • Yes, @MaheerAli, but it's a constant time operation so it doesn't affect the big O calculation. – Mark Mar 23 '19 at 07:15
  • O... Yes @Maheer Ali, probably based on time complexity, it may not be the best but the one I answered through the for loop did not satisfy the senior most UI dev. and asked me write a single line like the one shared. – rockey91 Mar 23 '19 at 07:25
2

This is the simplest code I found, It returns true or false for the given string mentioning the string contains all the alphabet in it or not.

new Set("<your_string>".toLowerCase().replace(/[^a-z]/g, "") ).size === 26

Example:

new Set("A quick brown fox jumps over the lazy dog".toLowerCase().replace(/[^a-z]/g, "") ).size === 26

Any other simplest form of code can be helpful. Please share it.

Thanks!

rockey91
  • 142
  • 2
  • 10
1

I believe this is the "simplest" w.r.t. computational complexity, requiring O(1) space (to store the character frequency table, assuming a fixed upper-bound possible input alphabet) and O(n) time as it iterates over the input string only once (plus a constant-time for the final check over the alphabet string).

var inputString = "Jaded zombies acted quaintly but kept driving their oxen forward";

var charCounts = {};
for( var i = 0; i < inputString.length; i++ ) {
    var c = inputString.at( i ).toLower();
    if( charCounts[c] ) charCounts[c]++;
    else                charCounts[c] = 1;
}

var alphabet = "abcdefghijklmnopqrstuvwyz";
for( var a = 0; a < alphabet.length; a++ ) {
    if( !charCounts[ alphabet.at(a) ] ) {
        console.log( "char %s does not appear in input string.", alphabet.at(a) );
    }
}
Dai
  • 141,631
  • 28
  • 261
  • 374
  • Thanks @Dai for sharing your answer based on time complexity. But the one am trying to showcase is the simplest code. Probably a single line one as I was asked by a senior most front-end developer. – rockey91 Mar 23 '19 at 07:22
1

As I look at it again, I can provide one tiny improvement to your code:

new Set("<your_string>".toLowerCase().replace(/[^a-z]/g, "").split("")).size === 26 .

Remove the 'i' flag on the regex because it's lowercased.

Chris Happy
  • 7,088
  • 2
  • 22
  • 49
  • 1
    Yes @Chris Happy, we don't need to use case insensitivity in replace regex as we have already used toLowerCase. Thanks! – rockey91 Mar 23 '19 at 07:26
1

Here is a different way to due it using String.fromCharCode() and every()

const allLetters = (str) => Array.from({length:26}).map((x,i) => String.fromCharCode(i+97)).every(a => str.toLowerCase().includes(a));
console.log(allLetters("abcdefghijklmnopqrstuvwxyz"));

Or you can hardcode all the alphabets.

const allLetters = (str) => [..."abcdefghijklmnopqrstuvwxyz"].every(x => str.toLowerCase().includes(x));

console.log(allLetters('abcdefghijklmnopqrstuvwxyz'))
console.log(allLetters('abcdefghijklmnopqyz'))
Maheer Ali
  • 35,834
  • 5
  • 42
  • 73
1
function isPangram(sentence){
   let lowerCased = sentence.toLowerCase();
   for(let char of 'abcdefghijklmnopqrstuvwxyz'){
      if(!lowerCased.includes(char)){
         return false
       }
    }
  return true
}

Here is another way using a for...of loop.