tags:

views:

140

answers:

4

I have two strings

Like

  "0101000000110110000010010011" and
  "0101XXXXXXX101100000100100XX"

it should compare each character and it should not consider if the character is X

for the above two strings the result is true.

now i'm using like

Iterating through the length of the string and replacing thecorresponding character in first string with X

is there any way to do this using LINQ

A: 

If you didn't have the X's, I would know the way. With the X's however, you can't do this with Linq as fas as I'm aware.

Anyway, just make them char arrays and do:

arrayOne.Distinct(arrayTwo).ToArray().Length == 0

Edit: Just occured to me, you can check if that result contains only X's. If it does, return true.

Jouke van der Maas
+5  A: 

This is reasonably easy in .NET 4, with the Zip method:

using System;
using System.Linq;

class Test
{
    static void Main()
    {
        string a = "0101000000110110000010010011";
        string b = "0101XXXXXXX101100000100100XX";

        var equal = !(a.Zip(b, (x, y) => new { x, y })
                       .Where(z => z.x != z.y && z.x != 'X' && z.y != 'X')
                       .Any());

        Console.WriteLine(equal);
    }
}

This basically zips the two strings together (considering them as sequences of characters) so we end up with sequences of pairs. We then try to find any pair where the values are different and neither value is 'X'. If any such pair exists, the strings are non-equal; otherwise they're equal.

EDIT: Thinking about it further, we can reverse the predicate and use All instead:

var equal = a.Zip(b, (x, y) => new { x, y })
             .All(z => z.x == z.y || z.x == 'X' || z.y == 'X');

If you're not using .NET 4, you could use the MoreLINQ implementation of Zip which would basically allow you to do the same thing.

Alternatively, you could zip the strings with their indexers like this:

var equal = Enumerable.Range(0, a.Length)
                      .Select(i => new { x = a[i], y = b[i] })
                      .All(z => z.x == z.y || z.x == 'X' || z.y == 'X');

That feels like it's cheating somewhat, but it works. Note that in all of these examples, I've assumed that you've already checked whether the input strings are the same length.

Jon Skeet
@ Jon Skeet : please post me a way to do this in .NET 3.5
Pramodh
@Pramodh: See my edits.
Jon Skeet
@ Jon Skeet: Thank you.......
Pramodh
@jon, i have added my answer.. is my approach recommended performance wise...??
Ramesh Vel
@Ramesh: That depends on what your performance *requirements* are. Your solution is not very fast compared to the fastest possible solution. *But if it doesn't have to be very fast then who cares?* State your performance requirement, and then measure your code to see if you meet it or not.
Eric Lippert
@Eric, i dont have an option to try out the zip method in .net 4.0 currently... :( i meant is it comparable to zip method in this scenario??
Ramesh Vel
@Ramesh: Try it! Then you'll know. I've put the source code for Zip on my blog. http://blogs.msdn.com/b/ericlippert/archive/2009/05/07/zip-me-up.aspx It's only a few lines of code. You can compare and see which one performs better.
Eric Lippert
Ramesh Vel
+4  A: 

You could create a custom comparer and then use the SequenceEqual method:

string s1 = "0101000000110110000010010011";
string s2 = "0101XXXXXXX101100000100100XX";

bool areEqual = s1.SequenceEqual(s2, new IgnoreXEqualityComparer());    // True

// ...

public class IgnoreXEqualityComparer : EqualityComparer<char>
{
    public override bool Equals(char x, char y)
    {
        return (x == 'X') || (y == 'X') || (x == y);
    }

    public override int GetHashCode(char obj)
    {
        throw new NotImplementedException();
    }
}
LukeH
I considered that... I just didn't like the idea of not implementing the hashing part.
Jon Skeet
@Jon: Yep, it does feel a bit wrong, even for a one-off use like this. If I was doing this in my own code then I'd probably avoid LINQ altogether and use a plain `for` loop, indexing into the strings directly.
LukeH
@LukeH: Yeah, so would I :)
Jon Skeet
A: 

This should work.

        var a1 = "0101000000110110000010010011";
        var a2 = "0101XXXXXXX101100000100100XX";
        var notmatched = a2.Select((cha, idx) =>
        {
            if (cha != 'X')
               return (cha == a1[idx]) ? true : false;
            else
                return true;
         }).Any(x => x == false);

        if (notmatched)
            //strings are not match
        else
            //strings are match

Cheers

Ramesh Vel
Any reason for calling ToCharArray() on each string? You can index into a string without converting it to an array.
Jon Skeet
@jon, sorry.. that s not necessary.. i ve updated my ans :(
Ramesh Vel
@jon, i called ToCharArray() because VS 2008 doenst show the string extension methods.... later i found this is the reason http://stackoverflow.com/questions/345883/why-doesnt-vs-2008-display-extension-methods-in-intellisense-for-string-class.. bloody confusion..
Ramesh Vel