Finding Isogram Word An isogram (also known as a "nonpattern word") is a word or phrase without a repeating letter, however spaces and hyphens are allowed to appear multiple times.

The IsIsogram() method takes a string and returns boolean value. 


INPUT: anik      OUTPUT: true
INPUT: A nika    OUTPUT: false


Approach 01: Using Dictionary&lt;TKey, TValue&gt;

static bool IsIsogram(string str)
    {
        //create a dictionary with 26 keys and assign false as default value
        var storeOccurance = new Dictionary&lt;int, bool&gt;();
        for (int i = 0; i &lt;= 25; i++)
        {
            storeOccurance[i] = false;
        }

        str = Regex.Replace(str, "[ -]", ""); //ignore whitespace and dash

        //iterate over each character of the string
        foreach (var ch in str.ToLower())
        {
            //(ch - 'a') is used to calculate the key. Check if the character key has false as it's value,
            //meaning they were never stored
            if (!storeOccurance[ch - 'a'])
            {
                storeOccurance[ch - 'a'] = true; //assign true when they are stored in the dictionary
            }
            else //otherwise, if a character key has true as it's value then it means that it exists in the dictionary 
            {                   
                return false; //return false and exits the iteration..Multiple occurance in dictionary
                               //means the string has repeating character so it's not Isogram
            }
        }
        return true;
    }


Approach 02: Using HashSet&lt;T&gt;

static bool IsIsogram(string str)
    {
        //TRICK: HashSet&lt;T&gt;.Add(T) returns false if an item already exists in HashSet&lt;T&gt;,
        //otherwise returns true and add the character to the datastructure

        var charHash = new HashSet&lt;char&gt;();

        foreach (var ch in str.ToLower())
        {   
            //check if the charHash.Add() returns false, if it does then terminate
            //as it means the character already exists
            if (!charHash.Add(ch) &amp;&amp; char.IsLetter(ch))
                return false;               
        }
        return true; //otherwise return true
    }


Approach 03: Using LINQ

static bool IsIsogram(string str)
    {                                    //Suppose "anik a" is a given string
        return str.Where(char.IsLetter) //filter only the letters ||here- only a, n, i, k, a will be taken 
                  .GroupBy(char.ToLower) //create group by characters(and transform them to lowercase) || here, there will be a group for each character a, n, i, k
                  .All(g =&gt; g.Count() == 1); //for every group, count the number of it's element and check if it's 1 
                                            //|| here, 'a' group has 2 elements so it return false though other groups has only one element in their group
    }


Given those above approaches:


Which approach would you recommend regarding readability, clean code and performance?
Is there any scope for improvement in the existing approaches?
I like the second approach since it allows you to exit as soon as a false condition is reached and is simpler than the first.  I would offer one minor optimization, keep the check for isletter separate and only check for duplicate if isletter is true:

static bool IsIsogram(string str)
{
    //TRICK: HashSet&lt;T&gt;.Add(T) returns false if an item already exists in HashSet&lt;T&gt;,
    //otherwise returns true and add the character to the datastructure

    var charHash = new HashSet&lt;char&gt;();

    foreach (var ch in str.ToLower())
    {   
        //check if the charHash.Add() returns false, if it does then terminate
        //as it means the character already exists
        if(char.IsLetter(ch))
        {
            if (!charHash.Add(ch))
                return false; 
        }

    }
    return true; //otherwise return true
}