Find the max value in a grouped list using Linq - linq

I have a linq expression that returns transactions in groups. Each transaction has a numerical value and I now need to know what is the highest value from all the transactions returned. This value is held in a field called TransactionId
Here is the expression I am using to get the grouped list.
var transactions = ctx.MyTransactions
.Where (x => x.AdapterId == Id)
.GroupBy(x => x.DeviceTypeId);
I now need to write an expression that works on the “transactions” grouped list to find the “max” of the TransactionId field. I’ve tried different ideas but none seem to work with the grouped results. I’m new to linq so I’m not sure how to do this.

Have you tried finding the maximum in each group and then finding the maximum of that over all groups?
int max = transactions.Max(g => g.Max(t => t.TransactionId));
Or you could just query the database again:
int max = ctx.MyTransactions
.Where(x => x.AdapterId == Id)
.Max(t => t.TransactionId);

This will give you the max in each group
var transactionIds = ctx.MyTransactions
.Where (x => x.AdapterId == Id)
.GroupBy(x => x.DeviceTypeId,
g => new {
DeviceTypeId = g.Key,
MaxTransaction = g.Max(x => x.TransactionId)
});

Related

how to get the linq list having Ids from IEnumerable<Object>

The code below userModel.Carriers is the type of IEnumerable<CarrierModel>.
userModel.Carriers has a list of carriers having Ids. With those Ids, I want to get CarrierDivision usign linq. But, I can't get it right because linq sqlexpression is not compatible with IEnumerable expression.
userModel.Carriers = carriersForRegion.Select(carrier => Mapper.Map<CarrierModel>(carrier))
.ToList();
var carrierDivision = from c in db.CarrierDivision where c.Contains();
collection.Contains will generate .. WHERE CarrierId IN (1, 2, 3) sql query
var carrierIds = userModel.Carriers.Select(carrier => carrier.Id).ToArray();
var divisions = db.CarrierDivision
.Where(division => carrierIds.Contains(division.CarrierId))
.ToArray();
In case db.CarrierDivision returns IEnumerable(not database), then I would suggest to create HashSet of carrier ids.
var carrierIds = userModel.Carriers.Select(carrier => carrier.Id).ToHashSet();
var divisions = db.CarrierDivision
.Where(division => carrierIds.Contains(division.CarrierId))
.ToArray();
With HashSet search executed without extra enumerations - O(1)

LINQ query to return first item in an ordered grouping

Grouping is an area of LINQ that I haven't quite managed to get my head around yet. I have the following code:
var subTrips = tbTripData
.Where(t => selectedVehicleIds.Contains(t.VehicleID))
.Join(tbSubTripData,
t => t.TripID,
s => s.TripID,
(t, s) => new { t = t, s = s })
.Select(r =>
new SubTrip
{
VehicleID = r.t.VehicleID,
TripID = r.t.TripID,
Sequence = r.s.Sequence,
TripDistance = r.s.TripDistance,
Odometer = r.s.Odometer
})
.ToList();
I'm trying to figure out a LINQ query that will look at subTrips and for each VehicleID, find the first Odometer, i.e. the Odometer corresponding to the lowest TripID and Sequence values.
I've been poking at it for an hour but just can't figure it out. Can anyone offer some advice before I give up and write procedural code to do it?
UPDATE: To clarify, Sequence is the sequential number of each subtrip within a trip. So what I'm looking for is the Odometer from the first subtrip for each vehicle when the subtrips within each grouped VehicleID are ordered by TripID then by Sequence.
I'm not 100% what you're looking for. But this might get you started in the right direction.
var groupedList = (from s in subTrips
group s by s.VehicleID
into grp
select new
{
VehicleID = grp.Key,
Odometer = grp.OrderBy(ex => ex.TripID).Select(ex => ex.Odometer).First(),
TripID = grp.Min(ex => ex.TripID)
}
).ToList();
This will return the VehicleID, the Odometer corresponding to the lowest TripID, and the lowest TripID.

Is there a easy way to filter out unique elements using linq?

I have an xml document
<NumSet>
<num>1</num>
<num>2</num>
<num>2</num>
<num>3</num>
</NumSet>
I want unique elements shown up, ie 1 and 3. not distinct which will also bring out 2.
How to do that? Do I have to use Group? Is there any concise way to do that?
You are right, you can use GroupBy and filter group which has only one item by using Count() == 1:
var output = XDocument.Load(xmlFile)
.Descendants("num")
.Select(e => e.Value)
.GroupBy(x => x)
.Where(g => g.Count() == 1)
.Select(g => g.Key);
It sounds like you want a Distinct GroupBy query... Take a look at the Need help on Linq with group by and distinct post here on StackOverflow.
XElement xe = XElement.Parse(#"<NumSet><num>1</num><num>2</num><num>2</num><num>3</num></NumSet>");
var query = xe.Elements("num")
.GroupBy(x => x.Value)
.Where(x=>x.Count ()==1)
.Select (x => x);
To do what you need I'd say that yes, you need to use GrouBy, and then count the elements in each group, and return those that contains just one element. In code, this translates to:
var query = lst.GroupBy(x => x)
.Where(x => x.Count() == 1)
.Select(x => x.Key);

Linq To Entities Optional Distinct

Earlier I put a question on Stackoverflow about how to remove duplicate records in a list of objects, based on a particular property within each object.
I got the answer I was looking for (see below), a query which returns a distinct list of objects using MainHeadingID as the property to remove duplicates.
public IList<tblcours> GetAllCoursesByOrgID(int id)
{
return _UoW.tblcoursRepo.All.
Where(c => c.tblCourseCategoryLinks.Any(cl => cl.tblUnitCategory.tblUnit.ParentID == id))
.GroupBy(c => c.MainHeadingID)
.Select(g => g.FirstOrDefault())
.ToList();
}
However, now I need more help! Is there anyway of amending the query above so that, it only removes duplicate values when MainHeadingID is not equal to 180. I tried amending GroupBy line to
.GroupBy(c => c.MainHeadingID != 180)
However, this didn't work.
Any help would be much appreciated with this.
Thanks.
Following works for LINQ to SQL:
return _UoW.tblcoursRepo.All
.Where(c => c.tblCourseCategoryLinks.Any(cl => cl.tblUnitCategory.tblUnit.ParentID == id))
.GroupBy(c => c.MainHeadingID)
//.SelectMany(g => g.Key == 180 ? g : g.Take(1))
.SelectMany(g => g.Take(g.Key == 180 ? Int32.MaxValue : 1))
.ToList();
Comments: SelectMany in query above selects all items from group where MainHeadingID equals to 180, but it takes only one item form other groups (i.e. distinct result). Linq to SQL cannot translate commented out part, but thanks to #usr there is way around.
Linq to Entities cannot translate even simplified query. I think only option for you in this case is simple concating result of two queries:
Expression<Func<tblcours, bool>> predicate = x =>
x.tblCourseCategoryLinks.Any(cl => cl.tblUnitCategory.tblUnit.ParentID == id)
int headingId = 180;
return _UoW.tblcoursRepo.All
.Where(c => c.MainHeadingID != headingId)
.Where(predicate)
.GroupBy(c => c.MainHeadingID)
.Select(g => g.FirstOrDefault())
.Concat(_UoW.tblcoursRepo.All
.Where(c => c.MainHeadingID == headingId)
.Where(predicate))
.ToList();
lazyberezovsky's answer fails due to an EF bug (which is not surprising given the quality of EF's LINQ support). It can be made to work with a hack:
.SelectMany(g => g.Key == 180 ? g.Take(int.MaxValue) : g.Take(1))
or
.SelectMany(g => g.Take(g.Key == 180 ? int.MaxValue : 1))
Note that performance will not be particularly good due to the way this is translated to SQL.

Groupby and where clause in Linq

I am a newbie to Linq. I am trying to write a linq query to get a min value from a set of records. I need to use groupby, where , select and min function in the same query but i am having issues when using group by clause. here is the query I wrote
var data =newTrips.groupby (x => x.TripPath.TripPathLink.Link.Road.Name)
.Where(x => x.TripPath.PathNumber == pathnum)
.Select(x => x.TripPath.TripPathLink.Link.Speed).Min();
I am not able to use group by and where together it keeps giving error .
My query should
Select all the values.
filter it through the where clause (pathnum).
Groupby the road Name
finally get the min value.
can some one tell me what i am doing wrong and how to achieve the desired result.
Thanks,
Pawan
It's a little tricky not knowing the relationships between the data, but I think (without trying it) that this should give you want you want -- the minimum speed per road by name. Note that it will result in a collection of anonymous objects with Name and Speed properties.
var data = newTrips.Where(x => x.TripPath.PathNumber == pathnum)
.Select(x => x.TripPath.TripPathLink.Link)
.GroupBy(x => x.Road.Name)
.Select(g => new { Name = g.Key, Speed = g.Min(l => l.Speed) } );
Since I think you want the Trip which has the minimum speed, rather than the speed, and I'm assuming a different data structure, I'll add to tvanfosson's answer:
var pathnum = 1;
var trips = from trip in newTrips
where trip.TripPath.PathNumber == pathnum
group trip by trip.TripPath.TripPathLink.Link.Road.Name into g
let minSpeed = g.Min(t => t.TripPath.TripPathLink.Link.Speed)
select new {
Name = g.Key,
Trip = g.Single(t => t.TripPath.TripPathLink.Link.Speed == minSpeed) };
foreach (var t in trips)
{
Console.WriteLine("Name = {0}, TripId = {1}", t.Name, t.Trip.TripId);
}

Resources