How to merge result IQueryable<T> together? - linq

If I get two result IQueryable from different linq Query and I want to merge them together and return one as result, how to to this?
For example, if:
var q1 = (IQueryable<Person>).....;
var q2 = (IQueryable<Person>).....;
how to merge q1 and q2 together and get result like
var q = (IQueryable<Person>)q1.Union(q2);

You have it, q1.Union(q2). The Union is in the System.Linq namespace with Queryable.

You can try the Concat Method
Something like this
int[] i1 = new int[] { 1, 2, 3 };
int[] i2 = new int[] { 3, 4 };
//returns 5 values
var i3 = i1.AsQueryable().Concat(i2.AsQueryable());
//returns 4 values
var i4 = i1.AsQueryable().Union(i2.AsQueryable());
Union will only give you the DISTINCT values, Concat will give you the UNION ALL.

(q1.Union(q2)).AsQuerable()

With NHibernate Union is not possible.
You have to process on the client side instead of DB processing the union.
I convert IQueryable to IENumerable with AsEnumerable and then use Concat extension.
var allItems = q1.AsEnumerable().Concat(q2)
Regards,
Sebastian

Related

LINQ: how to do "flat" collection instead of "nested" [duplicate]

I have a LINQ query which returns IEnumerable<List<int>> but i want to return only List<int> so i want to merge all my record in my IEnumerable<List<int>> to only one array.
Example :
IEnumerable<List<int>> iList = from number in
(from no in Method() select no) select number;
I want to take all my result IEnumerable<List<int>> to only one List<int>
Hence, from source arrays:
[1,2,3,4] and [5,6,7]
I want only one array
[1,2,3,4,5,6,7]
Thanks
Try SelectMany()
var result = iList.SelectMany( i => i );
With query syntax:
var values =
from inner in outer
from value in inner
select value;
iList.SelectMany(x => x).ToArray()
If you have a List<List<int>> k you can do
List<int> flatList= k.SelectMany( v => v).ToList();
Like this?
var iList = Method().SelectMany(n => n);

Executing list of IEnumerable queries

I have multiple Link queries loading to a IEnumerable list
var queries = new List<IEnumerable<Customers>>();
queries.Add(from c in context.Customers where c.region = 'NE' select c);
queries.Add(from c in context.Customers where c.region = 'SW' select c);
//want count of customers in those two regions
var result = queries.Sum(q => Count());
However it is returning a count of the queries (2), not count of the Customers.
How can execute the List of IEnumerable queries?
The mistake is at the last line:
q => Count()
Instead of actually counting the elements in a sequence, which would be q => q.Count(), you are calling a method Count() of either a current instance or the current class.
Actually, there is no need to do two separate queries. Instead, use a single query:
var query = from c
in context.Customers
where c.region = 'NE' || c.region = 'SW'
select c;
var result = query.Count();
or, slightly shorter:
var result = context.Customers.Count(c => c.region = 'NE' || c.region = 'SW');

Filter LINQ query using items from an external list with Lambda

How do you rewrite this in lambda?
int[] productList = new int[] { 1, 2, 3, 4 };
var myProducts = from p in db.Products
where productList.Contains(p.ProductID)
select p;
Assuming that by "with lambda" you mean the "query syntax", you can rewrite your query like this:
var myProducts = db.Products.Where(p => productList.Contains(p.ProductID));
Same thing just move the logic within a Where call.
var myProducts = db.Products.Where(p => productList.Contains(p.ProductID));
http://msdn.microsoft.com/en-us/library/vstudio/bb397947.aspx
^ a quick read that compares query syntax to method syntax for a query to two.

Join 2 lists by order instead of condition in LINQ

How can I join 2 lists of equal lengths (to produce a 3rd list of equal length) where I do not want to specify a condition but simply rely on the order of items in the 2 lists.
Eg how can I join:
{1,2,3,4} with {5,6,7,8}
to produce:
{{1,5}, {2,6}, {3,7}, {4,8}}
I have tried the following:
from i in new []{1,2,3,4}
from j in new []{5,6,7,8}
select new { i, j }
but this produces a cross join. When I use join, I always need to specify the "on".
You could use Select in the first list, use the item index and access the element on the second list:
var a = new [] {1,2,3,4};
var b = new [] {5,6,7,8};
var qry = a.Select((i, index) => new {i, j = b[index]});
If you are using .Net 4.0, you can use the Zip extension method and Tuples.
var a = new [] {1,2,3,4};
var b = new [] {5,6,7,8};
var result = a.Zip(b, (an, bn) => Tuple.Create(an, bn));
Alternatively, you can keep them as arrays:
var resultArr = a.Zip(b, (an, bn) => new []{an, bn});
There is a half way solution, if you want to use query syntax. Half way in the sense that you need to use the Select method on both lists in order to get the indexes that you will use in the where clause.
int[] list1 = {1,2,3,4};
int[] list2 = {5,6,7,8};
var result = from item1 in list1.Select((value, index) => new {value, index})
from item2 in list2.Select((value, index) => new {value, index})
where item1.index == item2.index
select new {Value1 = item1.value, Value2 = item2.value};
The benefit with this solution is that it wont fail if the lists have different lengths, as the solution using the indexer would do.

DataTable Query

I am new to LINQ. I am trying to find the rows that does not exists in the second data table.
report_list and benchmark both type are : DataTable. Both these datatables are being populated using OleDbCommand,OleDbDataAdapter. I am getting an error "Specified cast is not valid." in foreach ... loop. I would appreciate your help.
var result = from a in report_list.AsEnumerable()
where !(from b in benchmark.AsEnumerable()
select b.Field<int>("bench_id")
)
.Contains(a.Field<int>("BenchmarkID"))
select a;
foreach (var c in result)
{
Console.WriteLine(c.Field<string>("Name"));
}
I don't know if I understood your question. Are you trying to get the items that exists in the first table but not in the second?
var first = new string[] { "b", "c" };
var second = new string[] { "a", "c" };
//find the itens that exist in "first" but not in "second"
var q = from f in first
where !second.Contains(f)
select f;
foreach (var s in q) {
Console.WriteLine(s);
}
//Prints:
//b
I suggest you to make the inner query first, once it does not depend on the outer record.
From a in report_list
Group Join b in benchmark On a.bench_id Equals b.bench_id Into g = Group
Where g.Count = 0
Select a
Note that this is VB syntax.
My suspicion is that one of the fields you are comparing is not an integer in the database. I believe that the invalid cast exception is being thrown by one of the Field<int>() calls since that is one of the three different exceptions that this method can throw. See docs here.
Perhaps use the .Except() extension to get the set difference of the two sets?
(from b in benchmark.AsEnumerable()
select new { id = b.Field<int>("bench_id")}).Except(
from a in report_list.AsEnumerable()
select new {id = a.Field<int>("BenchmarkID")})
Not actually sure of the precise syntax, but that should work by taking the ids in benchmark, and then removing all equivalent ids in report_list, leaving only the ids that don't match. (I hope this is the order you were after...)
Note: This is also assuming that the above issue mentioned by tvanfosson isn't also a problem

Resources