0

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

2
  • who said anything about SQL? This is possible.. when u say ignore.. do you just mean skip to next character? or if both are X skip? Commented Jul 21, 2010 at 12:24
  • You know that if you are parsing binary string as part of parsing someting like a network or telecomunication protocol you are totally going the wrong way. In this case you should really parse the data contained as a series of objects and compare the resulting objects... Commented Jul 21, 2010 at 12:33

4 Answers 4

5

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.

Sign up to request clarification or add additional context in comments.

5 Comments

@ Jon Skeet : please post me a way to do this in .NET 3.5
@jon, i have added my answer.. is my approach recommended performance wise...??
@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, 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: Try it! Then you'll know. I've put the source code for Zip on my blog. 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.
4

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();
    }
}

2 Comments

I considered that... I just didn't like the idea of not implementing the hashing part.
@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.
0

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

2 Comments

Any reason for calling ToCharArray() on each string? You can index into a string without converting it to an array.
@jon, i called ToCharArray() because VS 2008 doenst show the string extension methods.... later i found this is the reason stackoverflow.com/questions/345883/….. bloody confusion..
-1

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.