IEnumerable<List<T>> to List<T> - c#

I'm working on a query of in-memory objects:
var rankingSummary = resultSet
.Where(r => r.Accuracy >= 95 && r.Accuracy <= 105)
.Select(r => r.Results).Where(r => r.ResultType == 1)
.Select(r => r.Subjects)
Subjects is a List<Subject> property that the Result class has. Where I'm at now in the query is with an IEnumerable<List<Subject>>. What I would like is for them to all be joined into a single List as I have further querying to do based on the properties of each Subject. Is there an elegant or practical way to achieve this?

I believe this should work:
var rankingSummary = resultSet
.Where(r => r.Accuracy >= 95 && r.Accuracy <= 105)
.Select(r => r.Results).Where(r => r.ResultType == 1)
.SelectMany(r => r.Subjects)
.ToList();

What you're looking for is SelectMany.
var rankingSummary = resultSet
.Where(r => r.Accuracy >= 95 && r.Accuracy <= 105)
.Select(r => r.Results).Where(r => r.ResultType == 1)
.SelectMany(r => r.Subjects)
.ToList();

Related

convert SQL with subquery to LINQ (lamda expression)

Need help with converting this sql query
SELECT c.studentId, c.Name
FROM Classes c
WHERE c.Class = 'Math'
AND c.Grade IN 'yoklama', '2')
AND c.studentId IN (
SELECT c2.studentId
FROM Classes c2
WHERE c2.Class = 'Eng'
AND c.Grade IN ('yoklama', '2'))
I was trying like this but these keeps giving error that I am doing this wrong
var reportDtos = context.Classes.Where(c => pt.Class == 'Math' && c.Grade.HasValue
&& c.Grade == '2' || c.Grade == 'yoklama' && c.studentId.Contains(context.ParticipTests
.Where(x => x.Class == 'Math' &&x.Grade.HasValue && x.Grade == '2' || x.Grade == 'yoklama')
.ToList()
.Select(x => ))
.Include("Area")
.Include("Questions")
.Include("Class.Test")
.ToList()
.Select(pt => new ReportDto
{
...
}
First off, strings must always be double quoted " and not single quoted ' like you have some.
If you write some code by splitting up the steps it makes it more understandable.
var validGrades = new List<string> { "Yoklama", "2" };
var studentsInEnglish = context.ParticipTests
.Where(x => x.Class.Equals("Eng") && validGrades.Contains(x.Grade))
.Select(x => x.studentId);
var studentsInMath = context.Classes
.Where(x => x.Class.Equals("Math") && validGrades.Contains(x.Grade) && studentsInEnglish.Contains(x.studentId))
.Select(x => (x.studentId, x.Name));
Now with this, (if you really still want to) you can write a single query by plugging in and replacing.
var reportDtos = context.ParticipTests
.Where(
x => x.Class.Equals("Math") &&
new List<string> { "Yoklama", "2" }.Contains(x.Grade) &&
context.Classes
.Where(
y => y.Class.Equals("Eng") &&
new List<string> { "Yoklama", "2" }.Contains(y.Grade))
.Select(y => y.studentId)
.Contains(x.studentId))
.Select(x => (x.studentId, x.Name))
.ToList();
...But I like the first way better.

Use same, looked-up value across multiple linq Where clauses without looking up more than once

I have a LINQ query which has three Where clauses. In each Where clause I am looking up the same set of items in order to compare values:
var items = _umbracoHelper.GetPage(ItemsPage.ModelTypeAlias).Children
.Where(x => level1Category == 0 || x
.GetPropertyValue<IEnumerable<IPublishedContent>>(UmbracoAlias.Item.Categories)
.Select(y => y.Id).Contains(level1Category))
.Where(x => !level2Categories.Any() || x
.GetPropertyValue<IEnumerable<IPublishedContent>>(UmbracoAlias.Item.Categories)
.Select(y => y.Id).Intersect(level2Categories.AsEnumerable()).Any())
.Where(x => !level3Categories.Any() || x
.GetPropertyValue<IEnumerable<IPublishedContent>>(UmbracoAlias.Item.Categories)
.Select(y => y.Id).Intersect(level3Categories.AsEnumerable()).Any());
Is there a way I can get the value of UmbracoAlias.Items.Categories once and store that value to be used in the other where clauses without causing the GetPropertyValue method to execute more than once?
You can pair up each item with category IDs, like this:
var items = _umbracoHelper.GetPage(ItemsPage.ModelTypeAlias).Children
.Select(c => new {
Child = c
, CategoryIds = c
.GetPropertyValue<IEnumerable<IPublishedContent>>(UmbracoAlias.Item.Categories)
.Select(y => y.Id)
.ToList()
})
.Where(x => level1Category == 0 || x.CategoryIds.Contains(level1Category))
.Where(x => !level2Categories.Any() || x.CategoryIds.Intersect(level2Categories.AsEnumerable()).Any())
.Where(x => !level3Categories.Any() || x.CategoryIds.Intersect(level3Categories.AsEnumerable()).Any())
.Select(x => x.Child);
This does the filtering on children paired up with their category IDs, and then keeps only the Child object in the final projection.
You could further simplify this by combining all three Where clauses:
var items = _umbracoHelper.GetPage(ItemsPage.ModelTypeAlias).Children
.Where(c => {
var categoryIds = c
.GetPropertyValue<IEnumerable<IPublishedContent>>(UmbracoAlias.Item.Categories)
.Select(y => y.Id)
.ToList();
if (level1Category != 0 && !categoryIds.Contains(level1Category)) {
return false;
}
if (level2Categories.Any() && !categoryIds.Intersect(level2Categories.AsEnumerable()).Any()) {
return false;
}
if (level3Categories.Any() && !categoryIds.Intersect(level3Categories.AsEnumerable()).Any()) {
return false;
}
return true;
});

combine 2 queries from the same table into one linq query

I have 2 queries that are query the same table but with different parameters and I would like to combine into one ,
Query 1
//ToDo refactor
int myDayOfWeek = 0;
DateTime dt = DateTime.Today;
myDayOfWeek = (int)dt.DayOfWeek;
var todaysLecture = (from c in _context.LectureGigs.Where(g => g.IsWeekLy == true && (int)g.Days == (myDayOfWeek))
select c).ToList();
//results Ok 1 result
Query 2
var upCommingLecture = _context.LectureGigs
.Include(g => g.Artist).Include(g => g.Genre)
.Where(g => g.DateTime > DateTime.Now && !g.IsCanceled);
//results Ok 2 result
The Query I would like to create
var upCommingLecture = _context.LectureGigs
.Include(g => g.Artist).Include(g => g.Genre).Where(g => g.IsWeekLy == true && (int)g.Days == (myDayOfWeek))
.Where(g => g.DateTime > DateTime.Now && !g.IsCanceled);
//Error none but 0 result
I have also tried this
var upCommingLecture = _context.LectureGigs
.Include(g => g.Artist).Include(g => g.Genre)
.Where(g => g.DateTime > DateTime.Now && !g.IsCanceled && g.IsWeekLy==true &&(int)g.Days==(myDayOfWeek));
//Error none but 0 result
OR (||), not AND (&&)
var upCommingLecture = _context.LectureGigs
.Include(g => g.Artist).Include(g => g.Genre)
.Where(g => (g.DateTime > DateTime.Now && !g.IsCanceled)
|| (g.IsWeekLy==true &&(int)g.Days==(myDayOfWeek)));

How to optimize LINQ-2-SQL expression?

I have a fairly complicated query that would read from a table, then do group on CONTACT_ID, then select only those group with count of 1.
This query is fairly complicated and I have no idea how to optimize it in LINQ.
var linkTable = this.DB.Links
.Where(l=>l.INSTANCE_ID==123456 && l.CONTACT_ID.HasValue && l.ORGANISATION_ID.HasValue)
.Select(l => new { l.DEFAULT_LINKED_ORGANISATION, l.LINK_ID, l.CONTACT_ID });
var defaultOrganizationLinkQuery = linkTable
.Where(l => l.DEFAULT_LINKED_ORGANISATION)
.Select(l => l.LINK_ID);
var singleOrganizationLinkQuery = linkTable
.GroupBy(l => l.CONTACT_ID)
.Select(group => new
{
CONTACT_ID = group.Key,
contact_link_count = group.Count(),
LINK_ID = group.First().LINK_ID
})
.Where(l => l.contact_link_count == 1)
.Select(l => l.LINK_ID);
var merged = singleOrganizationLinkQuery.Union(defaultOrganizationLinkQuery);
I made shorter version, but I do not expect it to be faster. If it works and is not slower I would be satisfied:
var merged = this.DB.Links
.Where(l=>l.INSTANCE_ID==123456 && l.CONTACT_ID.HasValue && l.ORGANISATION_ID.HasValue)
.GroupBy(l => l.CONTACT_ID)
.SelectMany(s => s.Where(x => s.Count() == 1 || x.DEFAULT_LINKED_ORGANISATION)
.Select(link => link.LINK_ID));

Can you dynamically cast during runtime inside a linq statement?

Hello is there a way to dynamically cast inside the following code so I do not need a bunch of if statements with nearly identical code?
List<DateTime> dateTimeList = null;
if(_dataSeriesList[0].GetType().Name == "Class1")
{
dateTimeList =
_dataSeriesList.ConvertAll(x => (Class1) x)
.Where(d => d.Time >= min && d.Time <= max)
.OrderBy(t => t.Time)
.Select(d => d.Time)
.ToList();
}
else if(_dataSeriesList[0].GetType().Name == "Class2")
{
dateTimeList =
_dataSeriesList.ConvertAll(x => (Class2) x)
.Where(d => d.Time >= min && d.Time <= max)
.OrderBy(t => t.Time)
.Select(d => d.Time)
.ToList();
}
.
.
and so on
I tried using the following code:
public static T Cast<T>(object o)
{
return (T)o;
}
Type t2 = _dataSeriesList[0].GetType();
dateTimeList =
_dataSeriesList.ConvertAll(x => castMethod.Invoke(null, new object[] { x }))
.Where(d => d.Time >= min && d.Time <= max)
.OrderBy(t => t.Time)
.Select(d => d.Time)
.ToList();
But then the linq statement will not compile.
If they don't share a common base type you can do it like this:
dateTimeList =
_dataSeriesList.Select(x => {
if (x.GetType().Name == "Class1")
return ((Class1)x).Time;
else
return ((Class2)x).Time;
})
.Where(d => d >= min && d <= max)
.OrderBy(t => t)
.Select(d => d)
.ToList();
Since all you are doing is working with the time element you just select out the item of interest according to your rules and then use it in a common way.
Of course if what you are working with is more complicated you select that information instead.
This is fairly standard in Linq -- make a new type on the fly that you need in order to do your work.
((as has been pointed out in the comments "on the fly" is actually determined at compile time and not dynamic in the typical use of the word))

Categories

Resources