LINQ projection combining date and list - c#

I have a list of objects containg value and date of transaction.
DateTime Date { get ; set; }
double Value { get; set; }
I want to get the new grouped object which will contain date of transaction and list of values for this particular day.
I can retrieve both list and date but i dont know how to use projection to cast them into new object.
var res1 = ExpenseList.Where(p => p.Date == Convert.ToDateTime("01-12-2013"))
.Select(p => p.Value)
.ToList();
DateTime res2 = ExpenseList.Where(p => p.Date == Convert.ToDateTime("01-12-2013"))
.Select(p => p.Date)
.FirstOrDefault();
There might have been some confusion around I will post pictures to clarify
I have something like this in ExpenseList set of date and value
I want one Date and Collection of Values

To group all of the values for a particular day you'll want to use GroupBy
var groups = ExpenseList.GroupBy(expense => expense.Date,
expense => expense.Value);

ExpenseList.Where(p => p.Date == Convert.ToDateTime("01-12-2013"))
.Select(p => new MyObject {Date = p.Date, Value = p.Value})
.ToList();
Replace MyObject for the actual type you have defined.

Related

LINQ Query for Unsanitized Data

I have a List<MyData> where MyData contains a Location field.
This field is a string, and is normally in "City, State" format but sometimes will come in as "Unknown".
There is another field, DateField.
I need to return a list of MyData objects grouped by the year in DateField, grouped by the state portion of Location, if that exists. If it comes in as "Unknown" then I need to ignore that.
My thoughts are use RemoveAll() on the List<> where (r => r.Location.Split(",").Length == 0), or if it doesn't include a comma at all.
Then I will have sanitized data.
That leaves me with two questions:
Is this the correct approach, or can I just handle it all with one LINQ query?
What should this LINQ query look like? I am looking state totals by a year specific year, which is passed into the API as an int.
I hope that comes across clear. Thanks.
If I understood you correctly, you can try to do the following. Filter the data with known Location first, then group it by two keys, year from DateField and State, and finally select a result
var data = new List<MyData>();
var result = data.Where(l => l.Location != "Unknown")
.GroupBy(d => new { d.DateField.Year, State = d.Location.Split(",").LastOrDefault() })
.Select(g => new
{
g.Key.Year,
g.Key.State,
Total = g.Count()
});
This query removes an state with unkonwn and also group on year of datefield ans state part of location
var mydata = new List<MyData>();
mydata.Where(x => x.Location != "Unknown")
.GroupBy(x => new { x.DateField.Date.Year, State =
x.Location.Split(',').LastOrDefault() })
.Select(x => new {
Year = x.Key.Year,
Count = x.Count()
});

Convert to IEnumerable<DateTime> result of LINQ Query

I have a linq Query
var tListOfDates = tList.GroupBy(g => g.dateOfSlot)
.Select(s => new {s.Key.Value });
dateOfSlot is a DateTime value
How can I convert tListOfDates to IEnumerable<DateTime>
I've tried top cast the result, but it doesn't work.
You should drop anonymous class new {s.Key.Value } (you don't want it but DateTime):
var tListOfDates = tList
.GroupBy(g => g.dateOfSlot)
.Select(s => s.Key.Value);
It seems that dateOfSlot is of type DateTime?, not DateTime since you put s.Key.Value, not s.Key; if my guess is right you can put it as
var tListOfDates = tList
.Where(item => item.dateOfSlot.HasValue)
.Select(item => item.dateOfSlot.Value)
.Distinct();
A proposition,you take all dates and get the unique date by Distinct
var tListOfDates = tList.Select(g => g.dateOfSlot).Distinct();
I Solved with
IEnumerable<DateTime> tListOfDates = tList.Where(w => w.dateOfSlot.HasValue).Select(g => g.dateOfSlot).Distinct().ToArray().Cast<DateTime>();
May be there is something more that needed and the query can be simplified.
So you have an object tlist, which implements IEnumerable<MySlot>. We don't know a lot of MySlot, yet we know that every MySlot object has a DateTime property DateOfSlot.
The first part of your LINQ statement groups all MySlots in your tlist into groups of MySlots where every MySlot in the group has equal DateOfSlot:
tList.GroupBy(mySlot => mySlot.dateOfSlot)
Every group has a Key which contains this common DateOfSlot. So the Key is d DateTime object
The second part projects every group into one element:
.Select(group => new {group.Key.Value });
group.Key is a DateTime. The problem is that a Datetime does not have a property Value. Are you sure that DateOfSlot is a DateTime?
It's not entirely certain what you want.
I have an IEnumerable<MySlot> in tList, and I want all used DateOfSlot values in this list
var allUsedDateOfSlotValues = tList.Select(mySlot => mySlot.DateOfSlot);
But now I have duplicates, I don't want duplicates!
var allDistinctUsedDateOfSlotValues = tList
.Select(mySlot => mySlot.DateOfSlot)
.Distinct();
This will have the same result as your code:
var result = tList.GroupBy(mySlot => mySlot.DateOfSlot)
// result: groups of mySlots with same DateOfSlot
.Select(group => group.Key)
// result: distinct values of DateOfSlot

Group by some columns depending on values in Entity Framework

I have the following simple statement in my Entity Framework code:
query = query
.Where(c => c.NotificationType == NotificationType.AppMessage)
.GroupBy(c => c.ConversationId)
.Select(d => d.OrderByDescending(p => p.DateCreated).FirstOrDefault());
It simply finds the latest Notification based on a group by with conversationId and select latest. Easy.
However, this is ONLY what I want if c.NotificationType == NotificationType.AppMessage. If the column is different than AppMessage (c.NotificationType <> NotificationType.AppMessage), I just want the column. What I truly Want to write is a magical statement such as:
query = query
.Where(c => (c.NotificationType <> NotificationType.AppMessage)
|| ((c.NotificationType == NotificationType.AppMessage)
.GroupBy(c => c.ConversationId)
.Select(d => d.OrderByDescending(p => p.DateCreated).FirstOrDefault()));
But this doesn't make sense because the GroupBy/Select is based on the first where statement.
How do I solve this?
The simplest way is to compose UNION ALL query using Concat at the end of your original query:
query = query
.Where(c => c.NotificationType == NotificationType.AppMessage)
.GroupBy(c => c.ConversationId)
.Select(d => d.OrderByDescending(p => p.DateCreated).FirstOrDefault())
.Concat(query.Where(c => c.NotificationType != NotificationType.AppMessage));
public class EntityClass
{
public int NotificationType { get; set; }
public int ConversationId { get; set; }
public DateTime Created { get; set; }
public static EntityClass GetLastNotification(int convId)
{
var list = new List<EntityClass>(); // Fill the values
list = list
.GroupBy(i => i.ConversationId) // Group by ConversationId.
.ToDictionary(i => i.Key, n => n.ToList()) // Create dictionary.
.Where(i => i.Key == convId) // Filter by ConversationId.
.SelectMany(i => i.Value) // Project multiple lists to ONLY one list.
.ToList(); // Create list.
// Now, you can filter it:
// 0 - NotificationType.AppMessage
// I didn't get what exactly you want to filter there, but this should give you an idea.
var lastNotification = list.OrderByDescending(i => i.Created).FirstOrDefault(i => i.NotificationType == 0);
return lastNotification;
}
}
you filter your list with "GroupBy" based on ConversationId. Next, create a dictionary from the result and make only one list (SelectMany). Then, you already have one list where should be only records with ConversationId you want.
Last part is for filtering this list - you wanted to last notification with certain NotificationType. Should be working :)

Linq Select causes InvalidCastException

var courses = db.Courses.Select(course => new Model.Course() {
Dates = db.Dates
.Where(date => date.CourseID == course.ID)
.Select(date => date._Date.ToString())
.ToList()
});
return courses.ToList();
The return call causes System.InvalidCastException. If I remove Dates, there is no error.
Here's Course class:
public class Course {
public List<string> Dates { get; set; }
}
Screenshot from VS:
The .ToString() on your _Date column could be causing the InvalidCastException. Linq to SQL is trying to convert your _Date into a string using ToString() which does not exist in SQL. You will need to simply grab the date as is from SQL and convert to string in memory.
Try this:
// Grab from db list of courses and their dates.
// Put dates in a List of DateTime, but you can also use DateTime2.
// Note that courses will be an IQueryable.
var courses = db.Courses.Select(course => new List<DateTime> {
Dates = db.Dates
.Where(date => date.CourseID == course.ID)
.Select(date => date._Date).ToList()
});
// Extract data from SQL by calling our IQueryable's ToList() of method. This puts the data as a List in memory.
// Using the List.Select() method, convert dates to strings. This will return an IEnumerable.
// Convert the resulting IEnumerable back to a List.
return courses
.ToList()
.Select(course => new Model.Course
{
// Here, you are using the .NET Framework's DateTime.ToString()
// So you can use any formatting options available with that.
Dates = course.Dates.Select(date => date.ToString()).ToList()
})
.ToList();
You didn't show the complete model but I think you should rather be joining those two tables with a join and not a where similar to this:
var courses =
db.Courses
.Join(
db.Dates,
c => c.ID,
d => d.CourseID,
(c, d) => new
{
Course = c,
Dates = d
}
).ToList();

How to return custom objects using Except

I'm using ASP.NET MVC, C# and SQL Server.
I want to get a list of cars that are available for rent within a certain date, ie. not already rented out.
What I got now is something like taking all the cars from the cars table, except the ones that have an order at the specified date (instead of checking each car individually for an order):
var query = db.Cars.Select(r => r.ID)
.Except(db.Orders
.Where(o => (startDate >= o.RentalStart
&& startDate <= o.RentalReturn))
Select(r => r.Car.ID));
The problem is that I want to return a custom object, and I'm not sure how do that using except, so I could always get the ID, and based on the ID get the entire object with a different method/query.
But I'd like to get something like:
Select(c => new myModel
{
ID = c.ID,
property1 = c.property1,
property2 = c.property2,
property3 = c.property3,
property4 = c.property4,
});
What you can do is filter the Cars list where the ID is not contained in the set of invalid order IDs.
var invalidOrders = db.Orders
.Where(o => startDate >= o.RentalStart && startDate <= o.RentalReturn)
.Select(r => r.Car.ID)
var query = db.Cars.Where(car => !invalidOrders.Contains(car.ID));

Categories

Resources