Pangrams implementation using Linq This is a continuation of my LINQ stories from Pangrams-Hackerrank. Similarly, this challenge has been asked before in python Pangrams python Implementation but I have tried to accomplish this challenge using LINQ.

Here is a summary of the question


  Roy wanted to increase his typing speed for programming contests. So, his friend advised him to type the sentence "The quick brown fox jumps over the lazy dog" repeatedly, because it is a pangram. (Pangrams are sentences constructed by using every letter of the alphabet at least once.)
  
  After typing the sentence several times, Roy became bored with it. So he started to look for other pangrams.
  
  Given a sentence , tell Roy if it is a pangram or not.
  
  Input Format
  
  Input consists of a string .
  
  Constraints 
  
  Length of  can be at most 103(1&le;|s|≤103) and it may contain spaces, lower case and upper case letters. Lower-case and upper-case instances of a letter are considered the same.
  
  Output Format
  
  Output a line containing pangram if  is a pangram, otherwise output not pangram.


Sample Input

Input #1

We promptly judged antique ivory buckles for the next prize    


Input #2

We promptly judged antique ivory buckles for the prize 


Sample Output

Output #1

pangram


Output #2

not pangram


Explanation

In the first test case, the answer is pangram because the sentence contains all the letters of the English alphabet.

Here is my implementation

using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.IO;
class Solution {
    static void Main(String[] args) {
        /* Enter your code here. Read input from STDIN. Print output to STDOUT. Your class should be named Solution */

            string pangramInput = Console.ReadLine();
            var alphabet = Enumerable.Range(97, 26).Select((x) =&gt; (char)x);
            var pangramCheck = pangramInput.Replace(" ", "").ToLower().OrderBy((letter) =&gt; letter).Distinct().SequenceEqual(alphabet);
            string answer = pangramCheck ? "pangram" : "not pangram";
            Console.WriteLine(answer);
    }
}


Thoughts

I know this is a simple exercise and can be achieved without LINQ but the main idea is to know how to use LINQ functions. 


Is the use of LINQ right? are there other simpler alternatives?
First a review...

Long extension chains

With lengthy linq chains it's a good idea to break them into multiple lines. Especially here on CR so that we don't have to scroll horizontally.

String interpolation


string answer = pangramCheck ? "pangram" : "not pangram";



We could optimize it as:

var answer = $"{(pangramCheck ? string.Empty : "not ")}pangram";


or you can make it even prettier by encapsulating this logic in an extension:

public static string Negate(this string value, bool negate)
{
    return $"{(negate ? string.Empty : "not ")}{value}";
}


so you then have:

Console.WriteLine("pangram".Negate(isPangram));


Consistency


string text
string answer



Don't you like var for strings because you already use for the other two variables? ;-)

Magic numbers


Enumerable.Range(97, 26)



This would be easier to understand if you used constants:

const string alphabetLength = z - a + 1;
Enumerable.Range('a', alphabetLength)


Not LINQ


.Replace(" ", "").ToLower()



This two kill the linq idea of your question. Consider this instead:

text
    .Select(char.ToLower)
    .Where(char.IsLetter)




Alternative solution

Then an alternative version...

If using a HashSet&lt;char&gt; is still linq-ish enougth then I replaced the Distinct with the Aggregate that uses one and makes it na O(n) solution for the English aphabet:

const int alphabetLength = 'z' - 'a' + 1;
var isPangram =
    text
    .Select(char.ToLower)
    .Where(char.IsLetter)
    .Aggregate(new HashSet&lt;char&gt;(), (acc, next) =&gt; { acc.Add(next); return acc; })
    .Count == alphabetLength;




UPDATE

Well, I forgot that we don't have to scan the entire string. As soon as we have the required chars we can stop. So this improved version should be faster for long texts:

const int alphabetLength = 'z' - 'a' + 1;
var chars = new HashSet&lt;char&gt;();

var testedChars = text
    .Select(char.ToLower)
    .Where(char.IsLetter)
    .TakeWhile(x =&gt; { chars.Add(x); return chars.Count != alphabetLength; })
    .Count();

var isPangram = chars.Count == alphabetLength;