Linq To Entities Get 2nd Last entry In List - linq

I have the following code which returns a list of Objects.
var listOfLogins = _logService.GetLogEventsByItemID(137).ToList();
I would like to get the 2nd last object in this list.
Does anyone know how to do this using Linq to Entities?
Thanks.

var secondlast = _logService.GetLogEventsByItemID(137)
.Reverse()
.Skip(1)
.Take(1)
.FirstOrDefault();
Update
#Dherik makes a good point in his comment that .Reverse is not actually supported in LINQ to Entities and will result in the query being evaluated at the point of calling reverse, rather than at the point of calling .FirstOrDefault. See here for all (not) supported methods.
The alternative (LINQ to Entities friendly) solution requires that you have a suitable field to order by (which must be the case anyway otherwise "second last" has no relevance):
var secondlast = _logService.GetLogEventsByItemID(137)
.OrderByDescending(e => e.EventDate /* could be any db field */)
.Skip(1)
.Take(1)
.FirstOrDefault();

int[] items = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int item = items.Skip(items.Count() - 2).Take(1).Single();
//will return 9
like this?

Related

How to use OrderBy in Linq

I am using OrderBy, and I have figured out that I have to use OrderBy as a last method, or it will not work. Distinct operator does not grant that it will maintain the original order of values, or if I use Include, it cannot sort the children collection.
Is there any reason why I shouldn't do Orderby always last and don't worry if order is preserved?
Edit:
In general, is there any reason, like performance impact, why I should not use OrderBy last. Doesnt metter if I use EnityFramework to query a database or just querying some collection.
dbContext.EntityFramework.Distinct().OrderBy(o=> o.Something); // this will give me ordered result
dbContext.EntityFramework.OrderBy(o=> o.Something).Distinct().; // this will not, because Distinct doesnt preserve order.
Lets say that I want to Select only one property.
dbContext.EntityFramework.Select(o=> o.Selected).OrderBy(o=> o.Something);
Will order be faster if I order collection after one property selection? So in that case I should use Order last. And I am just asking is there any situation where ordering shoudnt be done as last command?
Is there any reason why I shouldn't do OrderBy always last
There may be reasons to use OrderBy not as the last statement. For example, the sort property may not be in the result:
var result = context.Entities
.OrderBy(e => e.Date)
.Select(e => e.Name);
Or you want a sorted collection as part of the result:
var result = context.Customers
.Select(c => new
{
Customer = c,
Orders = c.Orders.OrderBy(o => o.Date)
Address = c.Address
});
Will order be faster if I order collection after one property selection?
Your examples show that you're working with LINQ to Entities, so the statements will be translated into SQL. You will notice that...
context.Entities
.OrderBy(e => e.Name)
.Select(e => e.Name)
... and ...
context.Entities
.Select(e => e.Name)
.OrderBy(s => s)
... will produce exactly the same SQL. So there is no essential difference between both OrderBy positions.
Doesn't matter if I use Entity Framework to query a database or just querying some collection.
Well, that does matter. For example, if you do...
context.Entities
.OrderBy(e => e.Date)
.Select(e => e.Name)
.Distinct()
... you'll notice that the OrderBy is completely ignored by EF and the order of names is unpredictable.
However, if you do ...
context.Entities
.AsEnumerable() // Continue as LINQ to objects
.OrderBy(e => e.Date)
.Select(e => e.Name)
.Distinct()
... you'll see that the sort order is preserved in the distinct result. LINQ to objects clearly has a different strategy than LINQ to Entities. OrderBy at the end of the statement would have made both results equal.
To sum it up, I'd say that as a rule of the thumb, try to order as late as possible in a LINQ query. This will produce the most predictable results.
I don't know if you misundertood the meaning of Distinct. According to definition it does:
Returns distinct elements from a sequence by using the default equality comparer to compare values.
So if you have a list of int and you want to remove repeated values, you use Distinct. Distinct uses the default equality comparer and it does the comparison by comparing the current element to the next one. So, you have to sort first to get the expected result.
And about OrderBy method, in fact, it does the sort. So if you want to sort something and distinct after you use:
List<int> myNumbers = new List<int>{ 102, 2817, 82, 2, 1, 2, 1, 9, 4 };
Sorting and removing duplicated numbers
// returns 1, 2, 4, 9, 82, 102, 2817
var sortedUniques = myNumbers.OrderBy(n => n).Distinct();
Removing duplicated numbers and sorting
// returns 1, 1, 2, 2, 4, 9, 82, 102, 2817
// It occurs because the Distinct compares current number to the next one
var sortedUniques = myNumbers.Distinct().OrderBy(n => n);
Just removing duplicated numbers
// returns 102, 2817, 82, 2, 1, 9, 4
var sortedUniques = myNumbers.Distinct().OrderBy(n => n);
Just sorting
// returns 1, 1, 2, 2, 4, 9, 82, 102, 2817
var sortedUniques = myNumbers.Distinct().OrderBy(n => n);
I hope it helps you \o/

Can this Aggregate Lambda expression be converted to a LINQ query?

I have a list of integers summed by an Aggregate method using a Lambda expression:
var mylist = new int[] { 3, 4, 5 };
var result = mylist.Aggregate((a, b) => a + b);
As I understand it, a Lambda expression can always be converted to a LINQ query. How would such a LINQ query look for my example?
EDIT: I understand .Sum may be better to add the numbers in my example. But I would really like to know how this Aggregate will look with a LINQ Query instead.
It already IS a LINQ query, Aggregate is a LINQ operator, i'm assuming what you meant was how it would look like in the LINQ comprehension syntax? The comprehension syntax only has a few built in features (select , where, multiple selects, groupby etc), it doesn't have all operators built in so when you need one of those (such as aggregate) you wrap it around parenthèses and keep going with the regular syntax. Since there is nothing there except aggregate it's not possible to give an example so i'll go from a different query:
var mylist = new int[] { 3, 4, 5, 6, 7, 8 };
var result = mylist
.Where(item=>item %2 == 0)
.Aggregate((a, b) => a + b);
var ComprehensiveResult =
(from item in mylist
where item % 2 == 0
select item)
.Aggregate((a, b) => a + b);
Comprehensive syntax is more of a "LINQ for people coming from SQL introduction", there's nothing you can do in it that you can't do with plain using the operators but the reverse isn't true as not all operators have built in replacements. The only thing that comes to mind where Comprehensive syntax is better (aside from personal taste) is multiple selects to generate a cartesian product which is much harder to maintain in plain method syntax.
In this case Aggregate function adds numbers each other. So, the equivalent function is SUM:
var qry = mylist.Sum(x=>x);
or
var qry = (from n in mylist select n).Sum();
[EDIT]
OP has added extra information to the question without informing me about that.
Yes, it's possible to "convert" Aggregate function into linq query, but extension method is needed. See this article: Cumulating values with LINQ

Filter Enums based on List in LINQ

I Have a Enum
public enum ProcessStatus: byte
{
NotStarted = 0,
PreCheckStarted= 1,
PreCheckCompleted= 2,
Processing= 3,
Failed= 4,
Completed= 5,
Closed= 6
}
in Table we have entries like 0,3,5,6
we need list of Enums based on some criteria and criteria is List which contains 0,1,2
i am able to get all Enums as List Like
Enum.GetValues(typeof(ProcessStatus)).OfType<ProcessStatus>()
and have
List<byte> processListIDs
which contains IDs
i want
IEnumerable<ProcessStatus> filtered based on ids in processListIDs using LINQ.
Thanks in Advance
You can use Intersect with better performance:
var enumList = Enum.GetValues(typeof (ProcessStatus))
.OfType<ProcessStatus>().Cast<byte>();
var result = enumList.Intersect(processListIDs)
.Cast<ProcessStatus>();
var res =
processStatusCollection.Where(item => processListIDs.Contains((int)item));
You could use Enum.TryParse<TEnum>:
List<byte> processListIDs = new List<byte>() { 0, 3, 5, 6 };
ProcessStatus ps = ProcessStatus.NotStarted;
IEnumerable<ProcessStatus> status = processListIDs
.Where(p => Enum.TryParse<ProcessStatus>(p.ToString(), out ps))
.Select(p => ps);
Try this,
var p = new List<byte>() { 1, 2, 3, 4, 6 };
IEnumerable<ProcessStatus> result = p.Select(o => (ProcessStatus)Enum.Parse(typeof(ProcessStatus), o.ToString()));
/// do something with result

Entity Framework Linq - how to get groups that contain all your data

Here a sample dataset:
OrderProduct is a table that contains the productIds that were part of a given order.
Note: OrderProduct is a database table and I am using EF.
OrderId, ProductId
1, 1
2, 2
3, 4
3, 5
4, 5
4, 2
5, 2
5, 3
What I want to be able to do is find an order that contains only the productIds that I am searching for. So if my input was productIds 2,3, then I should get back OrderId 5.
I know how I can group data, but I am unsure of how to perform the select on the group.
Here is what I have:
var q = from op in OrderProduct
group op by op.OrderId into orderGroup
select orderGroup;
Not sure how to proceed from here
IEnumerable<int> products = new List<int> {2, 3};
IEnumerable<OrderProduct> orderProducts = new List<OrderProduct>
{
new OrderProduct(1, 1),
new OrderProduct(2, 2),
new OrderProduct(3, 4),
new OrderProduct(3, 5),
new OrderProduct(4, 5),
new OrderProduct(4, 2),
new OrderProduct(5, 2),
new OrderProduct(5, 3),
};
var orders =
(from op in orderProducts
group op by op.OrderId into orderGroup
//magic goes there
where !products.Except(orderGroup.Select(x => x.ProductId)).Any()
select orderGroup);
//outputs 5
orders.Select(x => x.Key).ToList().ForEach(Console.WriteLine);
Or you can have another version as pointed in another answer, just replace
where !products.Except(orderGroup.Select(x => x.ProductId)).Any()
on
where products.All(pid => orderGroup.Any(op => op.ProductId == pid))
second one will have ~ 15% better performance (I've checked that)
Edit
According to the last requirement change, that you need orders that contain not all productIds you are searching, but exactly those and only those productIds, I wrote an updated version:
var orders =
(from op in orderProducts
group op by op.OrderId into orderGroup
//this line was added
where orderGroup.Count() == products.Count()
where !products.Except(orderGroup.Select(x => x.ProductId)).Any()
select orderGroup);
So the only thing you'll need is to add a precondition ensuring that collections contains the same amount of elements, it will work for both previous queries, and as a bonus I suggest 3rd version of the most important where condition:
where orderGroup.Select(x => x.ProductId).Intersect(products).Count() == orderGroup.Count()
At first glance, I'd try something like this:
var prodIds = new[] {2, 3};
from o in context.Orders
where prodIds.All(pid => o.OrderProducts.Any(op => op.ProductId == pid))
select o
In plain language: "get the orders that have a product with every ID in the given list."
Update
Since it appears you are using LINQ to SQL rather than LINQ to Entities, here's another approach:
var q = context.Orders;
foreach(var pid in prodIds)
{
q = q.Where(o => o.OrderProducts.Any(op => op.ProductId == pid));
}
Rather than using a single LINQ statement, you essentially build the query piecemeal.
Thanks to StriplingWarrior's answer I managed to figure this out. Not sure if this is the best way to do this, but it works.
List<int> prodIds = new List<int>{2,3};
var q = from o in Orders
//get all orderproducts that contain products in the ProdId list
where o.OrderProducts.All(op => prodIds.Contains(op.ProductId))
//now group the OrderProducts by the Orders
select from op in o.OrderProducts
group op by op.OrderId into opGroup
//select only those groups that have the same count as the prodId list
where opGroup.Count() == prodIds.Count()
select opGroup;
//get rid of any groups that may be empty
q = q.Where(fi => fi.Count()> 0);
(I am using LinqPad, which is why the query looks a little funky - no context, etc)

Using Linq to create crosstab results [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Is it possible to Pivot data using LINQ?
I'm wondering if its at all possible to create crosstab style results with Linq.
I have some data that looks like the following:
var list = new[]
{
new {GroupId = 1, Country = "UK", Value = 10},
new {GroupId = 1, Country = "FR", Value = 12},
new {GroupId = 1, Country = "US", Value = 18},
new {GroupId = 2, Country = "UK", Value = 54},
new {GroupId = 2, Country = "FR", Value = 55},
new {GroupId = 2, Country = "UK", Value = 56}
};
and I'm trying to output to a repeater control something like the following:
GroupId.....UK.....FR.....US
1...........10.....12.....18
2...........54.....55.....56
Its the dynamic columns that are causing my problems. Any solutions to this?
You need a runtimy class to hold these runtimy results. How about xml?
XElement result = new XElement("result",
list.GroupBy(i => i.GroupId)
.Select(g =>
new XElement("Group", new XAttribute("GroupID", g.Key),
g.Select(i => new XAttribute(i.Country, i.Value))
)
)
);
Are you expecting multiple records per result cell? If so there would need to be some Summing (and more grouping) in there.
(this answer is proof of concept, not final result. There's several issues to address, such as: ordering of columns, missing cells, and so on).
After doing a quick search you might want to look at the ModuleBuilder, TypeBuilder, and FieldBuilder classes in System.Reflection.Emit. They allow you to create a class dynamically at runtime. Outside of that you would need to do grouping on your objects and then do something with the hierarchical results you get from LINQ. I am not sure of a way to dynamically create anonymous type fields at runtime, and that sounds like what would need to happen.
You could try using the dynamic linq library provided by MS. They have a number of overloads to extensions methods that take strings as arguments. They also have an expression parser that takes a string an emits a lambda expression. You should be able to create a dynamic select using them.
A word of warning though, you end up with a non-generic IQueryable rather than a generic IQueryable so you are a little bit limited on what you can do with the result, and you give up a bit of type safety, but that may be OK in your application...
The link for the dynamic linq stuff is
http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
There is a link where you can download the source code the the dynamic library, plus some nice illustrations of how you can use it.
var labResults = from lab in CoreLabResults
where lab.Patient == 8
group lab by new { lab.Patient, lab.TestNo, lab.CollectedDate }
into labtests
select new
{
labtests.Key.Patient,
labtests.Key.TestNo,
labtests.Key.CollectedDate,
MCHC = labtests.Where(lab => lab.TestVar == "MCHC").FirstOrDefault().Result,
LYABS = labtests.Where(lab => lab.TestVar == "LYABS").FirstOrDefault().Result,
TotalTests = labtests.Count()
}

Resources