Part - 14 LINQ Union Method

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 11

LINQ Union Method

The LINQ Union Method in C# is used to combine multiple data sources into one data source by
removing duplicate elements. There are two overloaded versions available for the LINQ Union Method
as shown below.

The one and only difference between the above two LINQ Union methods is that the second
overloaded version takes IEqualityComparer as an argument. That means when we are working with
Complex Data Types, in order to work as expected, we can use the overloaded method which takes
the IEqualityComparer parameter.

Examples to Understand LINQ Union Method using C#


Let us understand LINQ Union Method with an example. Please have a look at the below image. As
you can see in the below image, here we have two integer data sources i.e. DataSource 1 and Data
Source 2. DataSource 1 contains elements such as 1, 2, 3, 4, 5, and 6, and DataSource 2 contains
elements such as 1, 3, 5, 8, 9, and 10. If we want to retrieve all the elements from both collections by
removing the duplicate element i.e. if we want the result as 1, 2, 3, 4, 5, 6, 8, 9, and 10, then we need
to use the LINQ Union method.

LINQ Union Method Example using Method and Query Syntax:


The following example shows the use of the LINQ Union Method using both Method and Query
Syntax to fetch all elements from both collections by removing the duplicate elements. In query
syntax, there is no such operator called Union, so here we need to use the mixed syntax i.e. both the
query and method syntax to achieve the same.
using System.Collections.Generic;
using System;
using System.Linq;
namespace LINQDemo
{
class Program
{
static void Main(string[] args)
{
List<int> dataSource1 = new List<int>() { 1, 2, 3, 4, 5, 6 };
List<int> dataSource2 = new List<int>() { 1, 3, 5, 8, 9, 10 };

//Method Syntax
var MS = dataSource1.Union(dataSource2).ToList();

//Query Syntax
var QS = (from num in dataSource1
select num)
.Union(dataSource2).ToList();

foreach (var item in MS)


{
Console.WriteLine(item);
}

Console.ReadKey();
}
}
}
Run the application and you will see the output as expected i.e. 1 2 3 4 5 6 8 9 10

LINQ Union Method Example with String Array using C#:


Let us see an example to understand how LINQ Union Method works with string collection in C#.
Here, in the below example, we have two arrays of countries that also contain the same country name
and our requirement is to return all countries from both collections by removing the duplicate country
names.
using System;
using System.Linq;
namespace LINQDemo
{
class Program
{
static void Main(string[] args)
{
string[] dataSource1 = { "India", "USA", "UK", "Canada", "Srilanka" };
string[] dataSource2 = { "India", "uk", "Canada", "France", "Japan" };

//Method Syntax
var MS = dataSource1.Union(dataSource2).ToList();

//Query Syntax
var QS = (from country in dataSource1
select country)
.Union(dataSource2).ToList();

foreach (var item in MS)


{
Console.WriteLine(item);
}

Console.ReadKey();
}
}
}
Now run the application and it will give us the following output.
As you can see it displays the country UK twice. This is because the default comparer that is being
used by the LINQ Union method is case-insensitive. So, if you want to ignore the case-sensitive then
you need to use the other overloaded version of the Union method which
takes IEqualityComparer as an argument. Let us modify the Main method of the program class as
follows to use the StringComparer as an argument that implements
the IEqualityComparer interface.
using System;
using System.Linq;
namespace LINQDemo
{
class Program
{
static void Main(string[] args)
{
string[] dataSource1 = { "India", "USA", "UK", "Canada", "Srilanka" };
string[] dataSource2 = { "India", "uk", "Canada", "France", "Japan" };

//Method Syntax
var MS = dataSource1.Union(dataSource2,
StringComparer.OrdinalIgnoreCase).ToList();

//Query Syntax
var QS = (from country in dataSource1
select country)
.Union(dataSource2, StringComparer.OrdinalIgnoreCase).ToList();

foreach (var item in MS)


{
Console.WriteLine(item);
}

Console.ReadKey();
}
}
}

LINQ Union Method with Complex Type in C#:


The LINQ Union Method like other Set Methods (such as Distinct, Expect, and Intersect) also works in
a different manner when working with complex data types such as Product, Employee, Student, etc.
Let us understand this with an example. Create a class file with the name Student.cs and then copy
and paste the following code into it.
namespace LINQDemo
{
public class Student
{
public int ID { get; set; }
public string Name { get; set; }
}
}
The above Student class is a very simple class with just two properties i.e. ID and Name. Let us say,
we have the following two data sources which contain some duplicate data.
As you can see in the above image, we have two collections of student data. And if you notice we
have two students Hina and Anurag appeared in both collections. Our requirement is to fetch all the
student names from both collections by removing the duplicate name. That means we want the
names Hina and Anurag to appear only once in the result. To achieve the same, we need to use the
LINQ Union Method. So, modify the Main method of the Program class as follows. In the below
example, from the first data source, we are fetching the student names by using the select method
and then we use the Union method and then we fetching the student names from the second data
source.
using System.Collections.Generic;
using System;
using System.Linq;
namespace LINQDemo
{
class Program
{
static void Main(string[] args)
{
List<Student> StudentCollection1 = new List<Student>()
{
new Student {ID = 101, Name = "Preety" },
new Student {ID = 102, Name = "Sambit" },
new Student {ID = 105, Name = "Hina"},
new Student {ID = 106, Name = "Anurag"},
};

List<Student> StudentCollection2 = new List<Student>()


{
new Student {ID = 105, Name = "Hina"},
new Student {ID = 106, Name = "Anurag"},
new Student {ID = 107, Name = "Pranaya"},
new Student {ID = 108, Name = "Santosh"},
};

//Method Syntax
var MS = StudentCollection1.Select(x => x.Name)
.Union(StudentCollection2.Select(y => y.Name)).ToList();
//Query Syntax
var QS = (from std in StudentCollection1
select std.Name)
.Union(StudentCollection2.Select(y => y.Name)).ToList();

foreach (var name in MS)


{
Console.WriteLine(name);
}

Console.ReadKey();
}
}
}
When you run the above code, you will get the output as expected as shown in the below image.
Here, you can see, the names Hina and Anurag appeared only once.

Now our requirement has changed and now we need to select all the information of all the students
from both collections by removing the duplicate students. In order to do this, let us modify the Main
Method of the Program class as shown below.
using System.Collections.Generic;
using System;
using System.Linq;
namespace LINQDemo
{
class Program
{
static void Main(string[] args)
{
List<Student> StudentCollection1 = new List<Student>()
{
new Student {ID = 101, Name = "Preety" },
new Student {ID = 102, Name = "Sambit" },
new Student {ID = 105, Name = "Hina"},
new Student {ID = 106, Name = "Anurag"},
};

List<Student> StudentCollection2 = new List<Student>()


{
new Student {ID = 105, Name = "Hina"},
new Student {ID = 106, Name = "Anurag"},
new Student {ID = 107, Name = "Pranaya"},
new Student {ID = 108, Name = "Santosh"},
};

//Method Syntax
var MS = StudentCollection1.Union(StudentCollection2).ToList();

//Query Syntax
var QS = (from std in StudentCollection1
select std).Union(StudentCollection2).ToList();
foreach (var student in MS)
{
Console.WriteLine($" ID : {student.ID} Name : {student.Name}");
}

Console.ReadKey();
}
}
}
Once you run the application, then you will see that it displays all the students without removing the
duplicate students as shown in the below image.

As you can see in the above output, the students Hina and Anurag appeared twice. This is because
the default comparer which is used for comparison by the LINQ Union Method is only checked
whether two object references are equal and not the individual property values of the complex object.
As we already discussed in our previous three articles, we can overcome this problem in many
different ways. Let us understand each way one by one.

Using IEqualityComparer Comparer with LINQ Union Method in C#:


In this approach, we need to create a class and then we need to implement
the IEqualityComparer interface and provide the implementation for the Equals and GetHashCode
method. So, create a class file with the name StudentComparer.cs and then copy and paste the
following code into it.
using System.Collections.Generic;
namespace LINQDemo
{
public class StudentComparer : IEqualityComparer<Student>
{
public bool Equals(Student x, Student y)
{
return x.ID == y.ID && x.Name == y.Name;
}

public int GetHashCode(Student obj)


{
return obj.ID.GetHashCode() ^ obj.Name.GetHashCode();
}
}
}
Next, we need to create an instance of StudentComparer class and then we need to pass that
instance to the Union method which takes IEqualityComparer as a parameter. So, modify the Main
method of the Program class as follows.
using System.Collections.Generic;
using System;
using System.Linq;
namespace LINQDemo
{
class Program
{
static void Main(string[] args)
{
List<Student> StudentCollection1 = new List<Student>()
{
new Student {ID = 101, Name = "Preety" },
new Student {ID = 102, Name = "Sambit" },
new Student {ID = 105, Name = "Hina"},
new Student {ID = 106, Name = "Anurag"},
};

List<Student> StudentCollection2 = new List<Student>()


{
new Student {ID = 105, Name = "Hina"},
new Student {ID = 106, Name = "Anurag"},
new Student {ID = 107, Name = "Pranaya"},
new Student {ID = 108, Name = "Santosh"},
};

StudentComparer studentComparer = new StudentComparer();

//Method Syntax
var MS = StudentCollection1
.Union(StudentCollection2, studentComparer).ToList();

//Query Syntax
var QS = (from std in StudentCollection1
select std)
.Union(StudentCollection2, studentComparer).ToList();

foreach (var student in MS)


{
Console.WriteLine($" ID : {student.ID} Name : {student.Name}");
}

Console.ReadKey();
}
}
}
With the above changes in place, run the application and you will get the output as expected as
shown in the below image. Here, you can see Hina and Anurag appeared only once.

Using Anonymous Type with Union Method in C#:


In this approach, we need to select all the individual properties to an anonymous type using the LINQ
select operator or Select Extension Method. The following program does exactly the same thing.
using System.Collections.Generic;
using System;
using System.Linq;
namespace LINQDemo
{
class Program
{
static void Main(string[] args)
{
List<Student> StudentCollection1 = new List<Student>()
{
new Student {ID = 101, Name = "Preety" },
new Student {ID = 102, Name = "Sambit" },
new Student {ID = 105, Name = "Hina"},
new Student {ID = 106, Name = "Anurag"},
};

List<Student> StudentCollection2 = new List<Student>()


{
new Student {ID = 105, Name = "Hina"},
new Student {ID = 106, Name = "Anurag"},
new Student {ID = 107, Name = "Pranaya"},
new Student {ID = 108, Name = "Santosh"},
};

//Method Syntax
var MS = StudentCollection1.Select(x => new { x.ID, x.Name })
.Union(StudentCollection2.Select(x => new { x.ID, x.Name })).ToList();

//Query Syntax
var QS = (from std in StudentCollection1
select new { std.ID, std.Name })
.Union(StudentCollection2.Select(x => new { x.ID, x.Name })).ToList();

foreach (var student in MS)


{
Console.WriteLine($" ID : {student.ID} Name : {student.Name}");
}

Console.ReadKey();
}
}
}
With the above changes in place, now run the application and you will get the output as expected as
shown in the below image.

Overriding Equals() and GetHashCode() Methods of Object Class


This is the third approach and in this approach, we need to override the Equals and GetHashCode() in
the Student class. As we know, by default, any type (predefined or user-defined) .NET Framework is
inherited from the Object class. That means the Student class is also inherited from the Object class.
So, we can override the Equals() and GetHashCode() methods of the Object class within the Student
class. So, modify the Student class as shown below. Here, we are overriding the Equals() and
GetHashCode() methods.
namespace LINQDemo
{
public class Student
{
public int ID { get; set; }
public string Name { get; set; }
public override bool Equals(object obj)
{
//As the obj parameter type is object, so we need to
//cast it to Student Type
return this.ID == ((Student)obj).ID && this.Name == ((Student)obj).Name;
}

public override int GetHashCode()


{
//Get the ID hash code value
int IDHashCode = this.ID.GetHashCode();
//Get the string HashCode Value
//Check for null refernece exception
int NameHashCode = this.Name == null ? 0 : this.Name.GetHashCode();
return IDHashCode ^ NameHashCode;
}
}
}
Next, we need to modify the Main method of the Program class as shown below. Here, we need to
use the overloaded version of the Intersect method which does not take any parameter.
using System.Collections.Generic;
using System;
using System.Linq;
namespace LINQDemo
{
class Program
{
static void Main(string[] args)
{
List<Student> StudentCollection1 = new List<Student>()
{
new Student {ID = 101, Name = "Preety" },
new Student {ID = 102, Name = "Sambit" },
new Student {ID = 105, Name = "Hina"},
new Student {ID = 106, Name = "Anurag"},
};

List<Student> StudentCollection2 = new List<Student>()


{
new Student {ID = 105, Name = "Hina"},
new Student {ID = 106, Name = "Anurag"},
new Student {ID = 107, Name = "Pranaya"},
new Student {ID = 108, Name = "Santosh"},
};

//Method Syntax
var MS = StudentCollection1.Union(StudentCollection2).ToList();

//Query Syntax
var QS = (from std in StudentCollection1
select std).Union(StudentCollection2).ToList();

foreach (var student in MS)


{
Console.WriteLine($" ID : {student.ID} Name : {student.Name}");
}

Console.ReadKey();
}
}
}
Now run the application code and, you will get the same output as the previous two examples as
expected as shown in the below image.

Implementing IEquatble<T> Interface in C#


In this approach, we need to implement IEquatble<T> Interface in Student Class and we need to
implement the Equals Method of the IEquatble<T> Interface and we also need to override the
GetHashCode method of the Object class. So, modify the Student class as shown below.
using System;
namespace LINQDemo
{
public class Student : IEquatable<Student>
{
public int ID { get; set; }
public string Name { get; set; }

public bool Equals(Student other)


{
return this.ID.Equals(other.ID) && this.Name.Equals(other.Name);
}
public override int GetHashCode()
{
int IDHashCode = this.ID.GetHashCode();
int NameHashCode = this.Name == null ? 0 : this.Name.GetHashCode();
return IDHashCode ^ NameHashCode;
}
}
}
Here, first, we implement the Equals method of the IEquatable interface and then we override the
GetHashCode method of the Object class. With the above changes in place, now modify the Main
Method of the Program class as shown below.
using System.Collections.Generic;
using System;
using System.Linq;
namespace LINQDemo
{
class Program
{
static void Main(string[] args)
{
List<Student> StudentCollection1 = new List<Student>()
{
new Student {ID = 101, Name = "Preety" },
new Student {ID = 102, Name = "Sambit" },
new Student {ID = 105, Name = "Hina"},
new Student {ID = 106, Name = "Anurag"},
};

List<Student> StudentCollection2 = new List<Student>()


{
new Student {ID = 105, Name = "Hina"},
new Student {ID = 106, Name = "Anurag"},
new Student {ID = 107, Name = "Pranaya"},
new Student {ID = 108, Name = "Santosh"},
};

//Method Syntax
var MS = StudentCollection1.Union(StudentCollection2).ToList();

//Query Syntax
var QS = (from std in StudentCollection1
select std).Union(StudentCollection2).ToList();

foreach (var student in MS)


{
Console.WriteLine($" ID : {student.ID} Name : {student.Name}");
}

Console.ReadKey();
}
}
}
Now, run the application and you will also get the same output as expected as shown in the below
image.

You might also like