views:

119

answers:

3

Im writing my own LINQ reference but Im getting troubles with some of the more complicated operators implementations.

There is a Join implementation that takes a IEqualityComparer Im getting just crazy.

Im trying to understand it first before I write (obviously)

Image this two lists:

List<string> initials = new List<string> {"A", "B", "C", "D", "E"};

List<string> words = new List<string> {"Ant", "Crawl", "Pig", "Boat", "Elephant", "Arc"};

Nothing weird here. I want to join both lists by the Initial, something like:

Initial=A Word=Ant
Initial=A Word=Arc
Initial=B Word=Boat
...

I need a comparator, I wrote this:

public class InitialComparator : IEqualityComparer<string>
{
    public bool Equals(string x, string y)
    {
        return x.StartsWith(y);
    }

    public int GetHashCode(string obj)
    {
        return obj[0].GetHashCode();
    }
}

The Join itself:

var blah = initials.Join(words,
                                  initial => initial,
                                  word => word,
                                  (initial, word) =>
                                  new {Initial = initial, Word = word},
                                  new InitialComparator());

It's the first time Im using HashCodes, after a good session of debugging I see that every word go to the comparator and look at its HashCode, if another word has the same HashCode it calls equals.

Since I want to compare just the initial I though that I just need the first letter Hash (Am I wrong?)

The thing is that this is not working correctly. Its says that "Ant" and "Arc" are equals, Ok, its comparing every word in the same list or not, But it adds only the last word it finds, in this case Arc, ignoring Ant and Ant is equals to "A" too...

If I put "Ant" and "Ant" it add both.

In short, What is the way of doing something like that? I know that Im doing something wrong.

Thank you.

A: 

I'm not sure why you're seeing this behavior, but I think using "SelectMany" would be a more straightforward approach and (more importantly) has the behavior you want:

var blah =
    from word in words
    from initial in initials
    where (word.StartsWith(initial))
    select new { Initial = initial, Word = word };

I prefer to use the comprehension syntax where possible. "SelectMany" is invoked when there are multiple "from" clauses in a comprehension query.

Daniel Pratt
Yeah, But as I said im writting a LINQ operators' reference in spanish. Im now with the Join operator and I need an example for a Join with a IEqualityComparer. Something simple that doesn't need more operators if possible. I was thinking some hours for something not really stupid. I ended with that thing because is simple, but I can't get it working.
Jesus Rodriguez
+1  A: 

You don't actually need your own equality comparer, just join on the individual letter like so:

var mine = from i in initials
     join w in words on i[0] equals w[0]
     select new {
          Initial = i,
          Words = w
     };
Crispy
I have to use the comparer...
Jesus Rodriguez
Then I suppose you could just fix your Equals method, but I'm really curious as to why you have to use a custom comparator.'public bool Equals(string x, string y) { return x[0] == y[0];}'
Crispy
I said it twice.. Im writing a reference of all operators with all implementations, and one of these is Join + comparator. The problem was just the Equals method.
Jesus Rodriguez
A: 

As Crispy mentioned try x[0] == y[0] instead of x.StartsWith(y); That worked for me.

juharr