LINQ Max Date with group by - linq

I have a requirement to sort a list by 1) the number of times a distinct item appears and then 2) if the count of two distinct rows is the same, the most recently used date of that group.
My group by function and sorting by count is working without the date:
(from x in data
group x by new { x.Col1, x.Col2, x.Col3}
into g
let count = g.Count()
select new
{
g.Key.Col1,
g.Key.Col2,
g.Key.Col3,
count
}).OrderByDescending(x => x.count)
However, I have been unable to successfully add the date sort. I was trying to add the date column as an aggregate in the group by expression, but that doesn't work.
(from x in data
group x by new { x.Col1, x.Col2, x.Col3, MaxDate = x.CreatedDateTime.Max()}
into g
let count = g.Count()
select new
{
g.Key.Col1,
g.Key.Col2,
g.Key.Col3,
count,
g.Key.MaxDate
}).OrderByDescending(x => x.count).ThenByDescending(x => x.MaxDate)
I get why it doesn't work, I just can't think of another route to add the secondary sort. Any ideas are appreciated!

This is what you're looking for (I think)
from x in data
group x by new { x.Col1, x.Col2, x.Col3}
into g
let count = g.Count()
select new
{
g.Key.Col1,
g.Key.Col2,
g.Key.Col3,
MaxDate = g.Select(x => x.CreatedDateTime)
.OrderByDescending(d => d).FirstOrDefault(),
count
}).OrderByDescending(x => x.count).ThenByDescending(x => x.MaxDate)

How about:
var ordered = Elev8SnaTowelTables
.GroupBy(x => new { x.Col1, x.Col2, x.Col3 })
.OrderByDescending(g => g.Count())
.ThenByDescending(g => g.Max(x => x.CreatedDateTime));

Related

How to find all rows of items that have a part in common using LINQ?

I need to return all records (items) that has a part (X) so I can use that in a group or .GroupBy afterwards
Using this summary data:
ItemName PartName
1 A
1 B
2 A
3 C
So Item1 has two parts (A,B), etc...
I need a LINQ query that will
- find all items that have part A (i.e items 1 and 2)
- return all rows for all these items
1 A
1 B
2 A
Notice that the end result returned the row (1 B) because Item1 has PartA and so I need to get back all rows for Item1.
I was looking at something like:
let items = from data in summary where data.PartName == A select new { data.ItemName } // to get all the items I need
But then, now that I have that list I need to use it to get all the rows for all items listed, and I can't seem to figure it out ...
Actual Source Code (for reference):
NOTE:
Recipe = ITEM
Ingredient = PART
(I was just trying to make it simpler)
ViewFullRecipeGrouping = (
from data in ViewRecipeSummary
group data by data.RecipeName into recipeGroup
let fullIngredientGroups = recipeGroup.GroupBy(x => x.IngredientName)
select new ViewFullRecipe()
{
RecipeName = recipeGroup.Key,
RecipeIngredients = (
from ingredientGroup in fullIngredientGroups
select new GroupIngredient()
{
IngredientName = ingredientGroup.Key
}
).ToList(),
ViewGroupRecipes = (
from data in ViewRecipeSummary
// this is where I am looking to add the new logic to define something I can then use within the next select statement that has the right data based on the information I got earlier in this query.
let a = ViewRecipeSummary.GroupBy(x => x.RecipeName)
.Where(g => g.Any(x => x.IngredientName == recipeGroup.Key))
.Select(g => new ViewRecipe()
{
RecipeName = g.Key,
IngredientName = g.Select(x => x.IngredientName)
})
select new GroupRecipe()
{
// use the new stuff here
}).ToList(),
}).ToList();
Any help would be much appreciated.
Thanks,
I believe this does what you want:
var data = /* enumerable containing rows in your table */;
var part = "X";
var items = new HashSet<int>(data
.Where(x => x.PartName == part)
.Select(x => x.ItemName));
var query = data.Where(x => items.Contains(x.ItemName));
If I understand your comment at the end, I believe this also does what you want:
var query = data
.GroupBy(x => x.ItemName)
.Where(g => g.Any(x => x.PartName == part))
.Select(g => new
{
ItemName = g.Key,
PartNames = g.Select(x => x.PartName)
});

Linq select top 1 name of a highest score group

I have a list which is like below
Name Score Date
S1 2 15/02/2013
S1 4 15/02/2013
S2 0 15/02/2013
My desired out should be
S1 6 15/02/2013
for this i wrote LINQ code as
(from _data in _rawData
group _data by new { _data.Date, _data.Name } into gp orderby gp.Key.Date
select new
{
score = gp.Sum(_score => _score.Score),
store = gp.Max(_store => _store.Name),
Date = gp.Max(_Date => _Date.Date)
}).OrderByDescending(_score => _score.score)
.ToList().
ForEach(item => _timeLiner.Add(new TimeLiner()
{
id = _id++.ToString(),
start = item.auditDate.ToString(),
title = "TopStore: " + item.store
}
I tried with .Take(1).ToList(), Single(), SingleOrDefault(), First() but i failed to get desired output. Instead i am getting as
S1 6 15/02/2013
S2 0 15/02/2013
top is a new range variable, which holds summary data for top score name of a day
from d in _rawData
group d by d.Date into dateGroup
let top = dateGroup.GroupBy(x => x.Name)
.Select(g => new { Name = g.Key, Score = g.Sum(x => x.Score)})
.OrderByDescending(x => x.Score)
.First()
select new
{
Name = top.Name,
Score = top.Score,
Date = dateGroup.Key
}
The following should give you the desired output:
(from _data in _rawData
group _data by new { _data.Date, _data.Name } into gp orderby gp.Key.Date
select new
{
score = gp.Sum(_score => _score.Score),
store = gp.Max(_store => _store.Name),
Date = gp.Max(_Date => _Date.Date)
}).OrderByDescending(_score => _score.score)
.First();
Or, a little bit more readable:
_rawData.GroupBy(x => new { x.Date, x.Name })
.Select(g => new {
Score = g.Sum(x => x.Score),
Store = g.Key.Name,
Date = g.Key.Date
}
.OrderByDescending(x => x.Score)
.First()

Record numbers in ascending order in MVC3

I have following query:
var accounts =
from account in context.Accounts
from guranteer in account.Gurantors
select new AccountsReport
{
CreditRegistryId = account.CreditRegistryId,
AccountNumber = account.AccountNo,
DateOpened = account.DateOpened,
};
return accounts.AsEnumerable()
.Select((account, index) => new AccountsReport()
{
RecordNumber = FormattedRowNumber(account, index + 1),
CreditRegistryId = account.CreditRegistryId,
AccountNumber = FormattedAccountNumber(account.AccountType, account.AccountNumber)}).OrderByDescending(c => c.StateChangeDate);
It works fine except one problem and that is it returns records number in reverse order like 3, 2,1 because of .OrderByDescending(c => c.StateChangeDate);
Can I show the record number in ascendeing order while keeping the records in descending order.
Please suggest.
Thanks
Try using OrderBy on RecordNumber and then ThenByDescending on StateChangeDate
.OrderBy(c => c.RecordNumber).ThenByDescending(c => c.StateChangeDate);

Linq select distinct values with comparison

I have a list of objects. E.g. List<coin> where they contain a string(denom) and int(year).
If the list contains:
"Quarter", 1954
"Quarter", 1990
"Penny", 1925
"Nickel", 1900
"Nickel", 2000
How can I get a resultant list where it contains the unique values with just the most recent year? E.g.:
"Quarter", 1990
"Penny", 1925
"Nickel", 2000
You can do this by grouping by name, then either ordering and taking the first result, or by using something like MaxBy from MoreLINQ:
var query = coins.GroupBy(x => x.Name)
.Select(g => g.MaxBy(x => x.Year));
or
var query = coins.GroupBy(x => x.Name)
.Select(g => g.OrderByDescending(x => x.Year).First());
You can do this using group by like:
var query = from coin in myList
group coin by coin.Name into grouped
select new
{
Name = grouped.Key
Year = grouped.Max(x => x.Year)
};
For another sample like this, check out "max - grouped" in the 101 Linq examples: http://msdn.microsoft.com/en-us/vcsharp/aa336747#maxGrouped
var coins = new Coin[] { ... };
var recentCoins =
from coin in coins
group coin by coin.Denom into g
select new
{
Denom = g.Key,
MostRecentYear = g.Max(c => c.Year)
};

LINQ to SQL, select targets with max date

I ended up with this horrible code below, I can't get a better result now.
What is a better way of doing that?
It's about this part of my database:
EDIT
A Patient has a Subscription to multiple MonitoringObjects. Target records refer to these Subscriptions. I want to retrieve the target records with the newest date per Subscription for a given Patient and a Category of MonitoringObjects. These target records may have different max dates, as Targets can be added for Subscriptions to MonitoringsObjects independently.
var subs = db.Subscriptions.Where(p => p.PatientID == patID).Where(p => p.MonitoringObject.Category.Name == "Medication");
var targets1 = from t in db.Targets
where subs.Contains(t.Subscription)
select t;
var maxTa = from t in db.Targets
group t by t.SubscriptionID
into g
select new
{
Ky = g.Key,
Date = g.Max(p => p.Date)
};
var targets2 = from t in targets1
where maxTa.Select(p => p.Ky).Contains( t.SubscriptionID ) &&
maxTa.Select(p => p.Date).Contains( t.Date )
select t;
I am not exactly sure what this is trying to achieve, or what your datamodel looks like, but something like this?
var subs = db.Subscriptions.Where(p => p.PatientID == patID).Where(p => p.MonitoringObject.Category.Name == "Medication");
var targets = subs
.SelectMany(s => s.Targets)
.Where(t => t.Date == t.Subscription.Targets.Max(_t => _t.Date))

Resources