this-Me
this-Me

Reputation: 2145

Issue with LINQ SequenceEquals extension in C#

I was trying out possibilities to check a string to be an palindrome with the following logic

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Anagram solver");
        Console.WriteLine(IsPalindrome("HIMA", "AMHI").ToString());
        Console.ReadKey();
    }

    static bool IsPalindrome(string s1, string s2)
    {
        return s1.OrderBy(c => c).SequenceEqual(s2.OrderBy(c => c));
    }
}

My idea was to get character literals in a string, and compare with that of characters from another string to deduce for a possible palindrome. Is such a thing possible with LINQ SequenceEqual method ?

Looking from the sample above,

'H' shall be compared with 'A'  (default equality comparison)  
'I' shall be compared with 'M'
'M' shall be compared with 'H'    
'A' shall be compared with 'I'

Can any one guide me here.

Thanks and Cheers Srivatsa

Upvotes: 1

Views: 307

Answers (4)

Tim Schmelter
Tim Schmelter

Reputation: 460138

You could use this method:

public static bool IsPalindromWith(this string str1, string str2)
{
    if(str1 == null || str2 == null) return false;
    return str1.SequenceEqual(str2.Reverse());
}

Usage: bool isPalindrom = "HIMA".IsPalindromWith("AMIH");

However, it is a very simple approach which ignores many edge cases.


Here is a better version that takes at least the case into account:

public static bool IsPalindromWith(this string str1, string str2, StringComparison comparison = StringComparison.CurrentCultureIgnoreCase)
{
    if(str1 == null || str2 == null) return false;
    char[] str2Chars = str2.ToCharArray();
    Array.Reverse(str2Chars);
    return str1.Equals(new String(str2Chars), comparison);
}

Upvotes: 1

Jens Kloster
Jens Kloster

Reputation: 11277

To elaburate on the existing (and i my opinion corrent) answer by @feO2x

Try looking at it like this:

   static bool IsAnagram(string s1, string s2)
    {
        var lst1  = s1.OrderBy(c => c); //will result in { 'A','H','I', 'M' }
        var lst2 = s2.OrderBy(c => c); //will *also* result in { 'A','H','I', 'M' }

        return lst1.SequenceEqual(lst2);
    }

The OrderBy(...) destroys the original order which you are trying to test.

Simply removing them will solve your problem:

   static bool IsAnagram(string s1, string s2)
    {
        var lst1  = s1.AsEnumerable(); 
        var lst2 = s2.AsEnumerable(); 

        return lst1.SequenceEqual(lst2);
    }

Upvotes: 1

feO2x
feO2x

Reputation: 5728

In your case, "HIMA" and "AMHI" are sorted by the OrderBy LINQ function, which results in two collections containing the characters "AHIM". If you call SequenceEqual this returns true.

For SequenceEqual to return true, both collections have to have the same amount of elements in exactly the same order. No elements are allowed to be duplicated or stored at another position.

If you want to determine if two words are anagrams, that is exactly the functionality you want.

For palindromes, you could use the following:

public bool CheckPalindrome(string first, string second)
{
    if (first == null) throw new ArgumentNullException("first");
    if (second == null) throw new ArgumentNullExcpetion("second");

    return first.Reverse().SequenceEquals(second);
}

Upvotes: 2

brainless coder
brainless coder

Reputation: 6430

If you want palindrome then you should not order them, just reverse and match -

static bool IsPalindrome(string s1, string s2)
{
    return s1.SequenceEqual(s2.Reverse());
}

for case-insensitivity try -

static bool IsPalindrome(string s1, string s2)
{
    return s1.ToLower().SequenceEqual(s2.ToLower().Reverse());
}

Upvotes: 2

Related Questions