I cannot seem to combine 2 GroupBy statements in 1 linq expression..
For now i'm doing something like this:
double maxInvestment = 0;
foreach (var playerAction in TotalUserActions.GroupBy(p => p.Player))
{
var MaxInvestmentPerPlayer = playerAction.GroupBy(p => p.RoundId)
.Select(p => p.LastOrDefault())
.Sum(p=> p.BetSize);
if(MaxInvestmentPerPlayer > maxInvestment)
maxInvestment = MaxInvestmentPerPlayer;
}
What I would like to do is something like this...
double maxInvestment = TotalUserActions.GroupBy(p => p.Player)
.GroupBy(p => p.RoundId)
.Select(p => p.LastOrDefault())
.Sum(p=> p.BetSize);
But that wont work.. Can someone help me on this?
Thanks!
Looks like this is what you want, the key takeaway being the inner query is wrapped in an outer call to Select():
var maxInvestment = TotalUserActions.GroupBy(p => p.Player)
.Select(g => g.GroupBy(x => x.RoundId)
.Select(x => x.LastOrDefault())
.Sum(x => x.BetSize))
.Max();
I do question your use of LastOrDefault() though as, since you have not specified any ordering, you may as well use FirstOrDefault() and save the hassle of skipping to the last element.
Related
I have the following result:
var result = (from p1 in db.Table
select new ReportInform
{
DataValue = p1.DataValue,
SampleDate = p1.SampleDate
})
.Distinct()
.ToList();
// Next getting list of duplicate SampleDates
var duplicates = result.GroupBy(x => x.SampleDate)
.Where(g => g.Count() > 1)
.Select (x => x)
.ToList();
foreach (var r in result)
{
if (duplicates.Contains(r.SampleDate)) // get error here on incompatbility
{
r.SampleDate = r.SampleDate.Value.AddMilliseconds(index++);
}
}
Cannot convert from 'System.DateTime?' to 'System.Linq.IGrouping
That error is pretty clear but may not be at a first glance. As a programmer, you need to learn how to read, understand and make sense of compiler or runtime errors.
Anyhow it is complaining that it cannot convert DateTime? to System.Linq.IGrouping<System.DateTime, ReportInForm>. Why? Because this query returns an System.Linq.IGrouping<System.DateTime, ReportInForm>
var duplicates = result.GroupBy(x => x.SampleDate)
.Where(g => g.Count() > 1)
.Select (x => x)
.ToList();
The GroupBy method returns IGrouping<System.DateTime, ReportInForm> which has a Key and the Key is the thing you grouped by and a list of items in that group. You are grouping by SampleDate and checking if there are more than one items in that group and then selecting the group. Thus dulplicates has a list of IGrouping<System.DateTime, ReportInForm> and you are asking the runtime to check if it contains a DateTime? and it blows up at this line:
duplicates.Contains(r.SampleDate)
One way to fix this is: What you want to do is to select the key of that group. Thus do this:
.Select (x => x.Key)
If you are expecting duplicates to be of type List<DateTime?> then you meant to write this
.Select(x => x.Key)
instead of
.Select(x => x)
From this LINQ:
var inspectionItems = inspArchive.Select(x => x.InspectionItems);
I get this result in inspectionItems :
My question is how can I make using LINQ in elegant way to make from inspectionItems result above one array distincted by Id.
Like that:
You want the SelectMany() LINQ method:
var inspectionItems = inspArchive.SelectMany(x => x.InspectionItems);
If you only want distinct items by a particular property, then you can either implement an equality comparer to see if your inspection classes are equal, then call .Distinct(myInspectionEqualityComparer) at the end of your method chain, or you can do this:
var distinctInspectionItems = inspArchive.SelectMany(x => x.InspectionItems)
.GroupBy(i => i.Id)
.Select(group => group.First());
Without seeing more of your code, I think you want to use SelectMany and Distinct ?
var inspectionItems = inspArchive.SelectMany(x => x.InspectionItems).Distinct();
The question is unclear, but check if this works for you:
var inspectionItems = inspArchive.SelectMany(x => x.InspectionItems)
.GroupBy(x => x.ID)
.Select(g => g.First())
.ToArray();
This LINQ-to-SQL query works (testing in LINQpad):
var q5 = LOGs.Where(r => r.APP_NAME == "Toaster")
.GroupBy(pol => pol.CASE_NO)
.Select(grp => grp.First())
.OrderByDescending(l => l.WHEN);
q5.Dump();
However, that returns all columns for each row.
How can I refine the Select() part to specify certain columns?
I can do it in two steps by adding .ToList() to the query, then querying q5:
var q5a = q5.Select(r => new {CASE=r.CASE_NO, WHEN = r.WHEN});
q5a.Dump();
Can I accomplish that in one statement instead of two?
Thanks --
why don't you filter after where?
var q5 = LOGs.Where(r => r.APP_NAME == "Toaster")
.Select(r=> new{r.CASE_NO, r.WHEN})
.GroupBy(pol => pol.CASE_NO)
.Select(grp => grp.First())
.OrderByDescending(l => l.WHEN);
remembar that new {CASE=r.CASE_NO, WHEN = r.WHEN} creates a new anonymous type because of differents property names, new {r.CASE_NO, r.WHEN} doesn't !
How do I order the following? The orderBy doesnt recognise the x.Name.
var xRefsNames = db.CrossRefs.Where(x => pgNos.Contains(x.PG))
.Select(x => x.Name)
.Distinct()
.OrderBy(x=>x.Name);
Your select is projecting a different object, probably a string based on the name. You want to just order by x.
var xRefsNames = db.CrossRefs.Where(x => pgNos.Contains(x.PG))
.Select(x => x.Name)
.Distinct()
.OrderBy(x=>x);
hi I have the following code and would like to only make each union if a condition is true.
I Know I could write a select of if else but wanted to know if there is a slicker Linq way!?
//join the list into one and sort by seqnumber
SegmentList = Alist.Cast<BaseSegment>()
.Union(BList.Cast<BaseSegment>()).Union(CList.Cast<BaseSegment>())
.OrderBy(item => item.SegSeqNumber).ToList();
So given the above if ATest =true how do I only iclude Alist like wise if BTest && CTest are true how do I include only BList and Clist
Thanks
To do it in a LINQ style way with your checkboxes, something like:
SegmentList = Alist.Where(i => checkbox1.IsChecked).Cast<BaseSegment>()
.Union(BList.Where(i => checkbox2.IsChecked).Cast<BaseSegment>())
.Union(CList.Where(i => checkbox3.IsChecked).Cast<BaseSegment>())
.OrderBy(item => item.SegSeqNumber).ToList();
would work. But I don't think it is either very understandable or efficient.
Something like this?
SegmentList = Alist.Cast<BaseSegment>()
.Union(includeB ? BList.Cast<BaseSegment>() : Enumerable.Empty<BaseSegment>())
.Union(includeC ? CList.Cast<BaseSegment>() : Enumerable.Empty<BaseSegment>())
.OrderBy(item => item.SegSeqNumber)
.ToList();
This is not identical to your original (it will remove duplicates from Alist no matter what) but should be what you want.
For any more than 2 conditional unions, you would probably want a different query, something like:
var listsByCb = new Dictionary<CheckBox, MyListType>
{{ aListBox, aList}, {bListBox, bList}, {cListBox, cList}};
var segmentList = listsByCb.Where(kvp => kvp.Key.Checked)
.SelectMany(kvp => kvp.Value.Cast<BaseSegment>())
.Distinct();
.OrderBy(item => item.SegSeqNumber)
.ToList();
try something like
SegmentList = Alist.Cast<BaseSegment>().Where(z=>ATest)
.Union(BList.Cast<BaseSegment>().Where(x=>Btest)).Union(CList.Cast<BaseSegment>().Where(c=>Ctest))
.OrderBy(item => item.SegSeqNumber).ToList();
where class in each case will return all elements if corresponding test is true and will return no element otherwise. its completely untested though
Use a Where() clause for that, like following:
//join the list into one and sort by seqnumber
SegmentList =
Alist.Cast<BaseSegment>().Where(a => ATest(a))
.Union(
BList.Cast<BaseSegment>(.Where(b => BTest(b))
.Union(CList.Cast<BaseSegment>().Where(c => CTest(c))
.OrderBy(item => item.SegSeqNumber).ToList();
By the way, do you really need the last ToList()?