Dejan Janjušević
Dejan Janjušević

Reputation: 3230

Select from two IEnumerables using LINQ

This seems fairly easy but I can't focus.
Let's say I have got 2 classes defined like this:

class Class1
{
    public int Document;
    public decimal Amount;
}

class Class2
{
    public string Document;
    public decimal Amount;
}

There are IEnumerable<Class1> result1 and IEnumerable<Class2> result2 defined and filled with data.

I have a third class defined like this:

class ResultClass
{
    public string Document;
    public decimal? AmountFromClass1;
    public decimal? AmountFromClass2;
}

I want a LINQ query which selects some fields from the first result and some fields from the second result and puts them in a third result defined as List<ResultClass> result.
For example, if I have the first result (result1) populated like this:

  Document    Amount
     1         1.55
     2         2.55

and the second result (result2) populated like this:

  Document    Amount
   "d-1"        1.22
   "d-2"        2.22

I want to have the final result populated something like this (order doesn't matter):

  Document    AmountFromClass1    AmountFromClass2
    "1"             1.55                null
   "d-1"            null                1.22
    "2"             2.55                null
   "d-2"            null                2.22

Currently I do this using two foreach statements, like this:

List<ResultClass> result = new List<ResultClass>();

foreach (var o in result1)
    result.Add(new ResultClass 
    { 
        Document = o.Document.ToString(), 
        AmountFromClass1 = o.Amount, 
        AmountFromClass2 = null 
    });

foreach (var o in result2)
    result.Add(new ResultClass 
    { 
        Document = o.Document, 
        AmountFromClass1 = null, 
        AmountFromClass2 = o.Amount 
    });

But I would like to do this using LINQ.
Is it possible?

EDIT: TO REFINE THE QUESTION (also added the entity-framework tag)
As this is just a code example, I am aware that there might be no real benefits of doing this in a single LINQ statement as it would do the same.
However, I am looking for a performance improvement where result1 and result2 are actually IQueryables from LINQ-to-Entities, in a way so I could do something like this:

List<ResultClass> MyFunc()
{
    Database DB = new Database(); // object context
    var result1 = DB.Class1s.Where(...);
    var result2 = DB.Class2s.Where(...);
    return SomeMagic()
        .Select(x => new ResultFunc { ... })
        .ToList();
}

Upvotes: 1

Views: 1721

Answers (3)

Tilak
Tilak

Reputation: 30728

Based on output you need, seems like you need an Union

        var class1 = new List<Class1>();
        var class2 = new List<Class2>();
        class1.Add(new Class1 (){Document=1, Amount = 1.0M});
        class1.Add(new Class1 (){Document=2, Amount = 1.0M});
        class2.Add(new Class2 (){Document="1", Amount = 1.0M});
        class2.Add(new Class2 (){Document="3", Amount = 1.0M});
            var result = class1.Select(x=> new ResultClass{Document = x.Document.ToString(), AmountFromClass1=x.Amount, AmountFromClass2 = null}).Union(
                            class2.Select(x=> new ResultClass{Document = x.Document, AmountFromClass2=x.Amount, AmountFromClass1 = null})   );

If you want cross join then you can use query syntax with multiple from clauses. Example

Upvotes: 0

Viacheslav Smityukh
Viacheslav Smityukh

Reputation: 5843

This is you code converted into LINQ

var result = result1
  .Select(c => new ResultClass() { Document = c.Document.ToString(), AmountFromClass1 = c.Amount })
  .Concat(result2.Select(c => new ResultClass() { Document = c.Document, AmountFromClass2 = c.Amount }))
  .ToList();

Upvotes: 1

dtb
dtb

Reputation: 217401

Project each item in both collections to a ResultClass object and concatenate the two resulting enumerables:

var query1 = from o in result1
             select new ResultClass
             {
                 Document = o.Document.ToString(),
                 AmountFromClass1 = o.Amount
             };

var query2 = from o in result2
             select new ResultClass
             {
                 Document = o.Document,
                 AmountFromClass2 = o.Amount
             };

var result = query1.Concat(query2).ToList();

Upvotes: 4

Related Questions