2

I have an assignment where I have to join two lists of the same type (Customer). They have similar entries which I have to avoid repetitions.

This is my customer class:

class Customer
{
  private String _fName, _lName;
  private int _age, _cusIndex;
  private float _expenses;

  public Customer(String fName, String lName, int age, float expenses, int cusIndex)
  {
    this._fName = fName;
    this._lName = lName;
    this._age = age;
    this._expenses = expenses;
    this._cusIndex = cusIndex;
  }
}

So I have two List<Customer>s named customers1 and customers2. I need to join these two without using Collections methods (like customer1.Union(customer2).ToList(); But using Linq queries.

Here's the Linq query I wrote:

var joined = (from c1 in customers1
              join c2 in customers2
              on c1.CusIndex equals c2.CusIndex
              select new {c1, c2});

But this gives me the member who appear on both of the lists. But I need all, without repetition. Are there any solution ???

ThisaruG
  • 3,222
  • 7
  • 38
  • 60
  • 1. Override [Equals](https://msdn.microsoft.com/library/ms173147.aspx) and [GetHashCode](http://blogs.msdn.com/b/ericlippert/archive/2011/02/28/guidelines-and-rules-for-gethashcode.aspx) in your `Customer` class (to reflect that two customers are considered equal, if their `CusIndex` is equal). 2. `var joined = customers1.Concat(customers2).Distinct();` – Corak Nov 27 '15 at 05:08
  • 1
    It looks like there is no query equivalent for `Union` method. What is the reason of not using `Union` method? – Yeldar Kurmangaliyev Nov 27 '15 at 05:10
  • @Corak Yes. I've already done that. But the problem is, this query returns the Customers who are in both of the lists. But I need everyone – ThisaruG Nov 27 '15 at 06:04
  • @YeldarKurmangaliyev As I mentioned, this is an assignment :/ – ThisaruG Nov 27 '15 at 06:05
  • 1
    @ThisaruGuruge - [Concat](https://msdn.microsoft.com/library/bb302894.aspx) basically just enumerates *the whole* first enumerable *and then the whole* second enumerable. [Distinct](https://msdn.microsoft.com/library/bb348436.aspx) then basically skips all elements that have already been yielded. That's giving you, what you want: *everyone* (from both lists), but only *once*. But since [Union](https://msdn.microsoft.com/library/bb341731.aspx) seems to work for you (I guess it does the same under the hood), use that. :) – Corak Nov 27 '15 at 08:59
  • 1
    Yes, according to [referencesource](http://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs) it does. Relevant implementation (look for `UnionIterator`): `Set set = new Set(comparer); foreach (TSource element in first) if (set.Add(element)) yield return element; foreach (TSource element in second) if (set.Add(element)) yield return element;` – Corak Nov 27 '15 at 09:09
  • Thanks @Corak buddy !!! – ThisaruG Nov 27 '15 at 11:38

2 Answers2

8

It looks like there is no query equivalent for Union method. You will need to use this method either in method chain call or in your query.

If you look at MSDN documentation on returning the set union of two sequences, you will see the following official query:

var infoQuery =
    (from cust in db.Customers
    select cust.Country)
    .Union
        (from emp in db.Employees
        select emp.Country)
;

So, there are only two options in your case:

  1. Method chain:

    var joined = customers1.Union(customers2);
    
  2. LINQ query

    var joined = (from c1 in customers1
                  select c1)
                 .Union
                     (from c2 in customers2
                      select c2);
    
Yeldar Kurmangaliyev
  • 33,467
  • 12
  • 59
  • 101
1

Why not use Distinct to filter out the duplicates?

 var joined =  (from c1 in customers1
          join c2 in customers2
          on c1.CusIndex equals c2.CusIndex
          select new {c1, c2}).Distinct();

There is a nice extension in Microsoft.Ajax.Utilities. It has a function called DistinctBy, which may be more relevant in your case.

Kosala W
  • 2,133
  • 1
  • 15
  • 20
  • I used this. But when I tried to convert it into a new List using `ToList()` method, It gives me Error. `cannot implicitly convert type` – ThisaruG Nov 27 '15 at 06:01
  • This is similar to a [self join](http://www.tutorialspoint.com/sql/sql-self-joins.htm). ToList() will give you an anonymous collection. I am confused about what you are trying to achieve. You cannot cast an anonymous type to a known type. – Kosala W Nov 27 '15 at 06:37
  • As I mentioned, I need to join two Lists without repetitive elements. It's a part of an assignment ! – ThisaruG Nov 27 '15 at 06:47
  • 1
    Then you have to `Union` to combine two collections and then `Distinct` to filter out duplicates. Or you can use `Intersect`, then `Union` and then `Except`. There are many ways to do it. – Kosala W Nov 27 '15 at 07:22
  • Thank you for the help. I tried and succeed the method provided by @yeldarKurmangaliyev – ThisaruG Nov 27 '15 at 09:48