Geeks With Blogs
Marcin Kasprzykowski`s blog

 INTRODUCTION 

Some time ago I published an article describing in very little details GroupBy method that comes with LINQ framework. Now I want to show you on an example step by step how to use another LINQ`s method – GroupJoin. 

GroupJoin method is somewhat similar to the previous one. The only difference is that it additionally applies inner join operation on given collections. This operation is applied before grouping. If you would like to swap those operation`s order then use GroupBy method followed by using Join method instead.

In this article I will not describe what grouping by operation is in general. If you don`t feel comfortable with it then I suggest reading my previous article where it is explained in fairly simple way. 

 

GROUPJOIN METHOD SIGNATURE

The signature of this method looks a bit terrifying but don`t feel discouraged. Everything will should clear soon. Here it is:

public static IEnumerable<TResult> GroupJoin

<(Of <(TOuter, TInner, TKey, TResult>)>)

(this IEnumerable<(Of <(TOuter>)>),

IEnumerable<(Of <(TInner>)>),

Func<(Of <(TOuter, TKey>)>),

Func<(Of <(TInner, TKey>)>),

Func<(Of <(TOuter, IEnumerable<(Of <(TInner>)>), TResult>)>)) 

Just to remind you – the first parameter is preceded with keywork this which means that this is extension method. If you are not familiar with extensions methods I recommend this article: http://msdn.microsoft.com/en-us/library/bb383977.aspx.

There is also an additional optional parameter at the end of arguments list:

IEqualityComparer<(Of <(TKey>)>)

It simply allows you to pass custom comparer that will be used to compare collection`s keys. If you omit this argument, the default comparer will be used (which is just enough in most cases).

  

EXAMPLE

Example I prepared will be pretty similar to the one I used in previous article. It is pretty long but straightforward. So we also have collection of trains and each train is having a collection of carriages: 

    class Carriage
   {
        public int Length { get; set; }

   }

 

   class Train
   {
        public string Country { get; set; }
        public List<Carriage> Carriages { get; set; }
   }

 

Additionally I added a Depot class which will participate in join operation:

    class Depot
    {
        public string Location { get; set; }
    }

 

I made a collection of trains and initialized it with some data:

    List<Train> trains = new List<Train>(); 

    trains.Add(new Train()
    {
        Country = "usa",
        Carriages = new List<Carriage>() {
        new Carriage() { Length = 25 },
        new Carriage() { Length = 25 } }
    });

    trains.Add(new Train()
    {
        Country = "USA",
        Carriages = new List<Carriage>() {
        new Carriage() { Length = 20 },
        new Carriage() { Length = 20 },
        new Carriage() { Length = 18 } }
    });

    trains.Add(new Train()
    {
        Country = "Japan",
        Carriages = new List<Carriage>() {
        new Carriage() { Length = 22 },
        new Carriage() { Length = 22 },
        new Carriage() { Length = 19 },
        new Carriage() { Length = 19 } }
    });

    trains.Add(new Train()
    {
        Country = "japan",
        Carriages = new List<Carriage>() {
        new Carriage() { Length = 22 },
        new Carriage() { Length = 22 },
        new Carriage() { Length = 19 },
        new Carriage() { Length = 19 },
        new Carriage() { Length = 15 } }
    });

    trains.Add(new Train()
    {
        Country = "India",
        Carriages = new List<Carriage>() {
        new Carriage() { Length = 28 },
        new Carriage() { Length = 28 }}
    }); 

 

The last thing we need is the collection of depots also initialized appriopriately:

    List<Depot> depots = new List<Depot>();

    depots.Add(new Depot() { Location = "usa" });
    depots.Add(new Depot() { Location = "japan" });
    depots.Add(new Depot() { Location = "
india" });
 

 

GOAL

Our goal is to get a collection of objects containing:

  1. Location
  2. Collection of trains assigned depot in this location
  3. Collection of carriages of trains assigned depot in this location

 

USAGE OF GROUPJOIN METHOD

First of all we need to perform inner join operation on those two collections: trains and depots. Since each train will be assigned to one depot, depots collection will act as an outer collection in this case and trains will act as an inner collection. This said, first two arguments should be clear and obvious:

var result = depots.GroupJoin(trains

Next we need to specify outer and inner keys. ‘Key’ is basically a transformation. It is a way of telling the method which properties of depot and trains objects should be used in comparison. In this example country name will be used in join operation. To ensure that our example is not case-sensitive all compared strings will be made uppercase. Having this in mind, two further arguments should also be obvious:

var result = depots.GroupJoin(trains, (depot => depot.Location.ToUpper()), (train => train.Country.ToUpper())

Now it is turn for the last and most complex argument. It is our results set. Here we can specify what should be the output of this method. It is often pretty comfortable to use anonymous type here and I will do so. According to our goals, first information should be the country name:

var result = depots.GroupJoin(trains, (depot => depot.Location.ToUpper()), (train => train.Country.ToUpper()), (d, t) =>

                new { Location = d.Location

This value could also be taken from whichever train in given group (as all trains in given group belong to one depot, so they must be assigned to the same country). 

Next thing is te IEnumerable of all trains assigned to the given depot, which is exactly what ‘t’ parameter in lambda expression means:

var result = depots.GroupJoin(trains, (depot => depot.Location.ToUpper()), (train => train.Country.ToUpper()), (d, t) =>

                new { Location = d.Location, AssignedTrains = t

Last parameter is the IEnumerable of all carriages assigned to those trains. Using SelectMany method will solve this issue easily (this method ‘flattens’ the collections of collections into one collection):

var result = depots.GroupJoin(trains, (depot => depot.Location.ToUpper()), (train => train.Country.ToUpper()), (d, t) =>

                new { Location = d.Location, AssignedTrains = t, AssignedCarriages = t.SelectMany(tr => tr.Carriages) });
 
 

CONCLUSION

And this is it. Fairly simple if you have a good feeling of lambda expressions. Any questions are more than welcome. Happy coding!

 

REFERENCES

  1. http://msdn.microsoft.com/en-us/library/system.linq.enumerable.groupjoin.aspx
  2. http://msdn.microsoft.com/en-us/library/system.linq.enumerable.join.aspx
  3. http://msdn.microsoft.com/en-us/library/system.linq.enumerable.groupby.aspx
  4. http://www.hookedonlinq.com/GroupByOperator.ashx
  5. http://www.hookedonlinq.com/GroupJoinOperator.ashx

 

 

Posted on Wednesday, January 27, 2010 3:31 PM | Back to top


Comments on this post: GroupJoin method tutorial

# Korean Plastic Surgeon
Requesting Gravatar...
Hi… that was great stuff. I really like this subject. Could you tell me more … I would love to explore.
Left by Kyoung Charles Kim on Sep 26, 2011 7:32 AM

# re: GroupJoin method tutorial
Requesting Gravatar...
Thanks for the post.
Left by yesu on Apr 19, 2012 2:28 AM

Your comment:
 (will show your gravatar)


Copyright © Martinez | Powered by: GeeksWithBlogs.net