I have a list which contains dates and the same date can be repeated multiple times.
List<DateTime> dates = new List<DateTime>();
foreach (List<string> l in reservations)
{
var start = Convert.ToDateTime(l.First());
var end = Convert.ToDateTime(l.Last());
for (var date = start.Date; date.Date <= end.Date; date = date.AddDays(1))
dates.Add(date);
}
I want to find the date with maximum occurrences. If there are multiple dates with the maximum occurrence, I need to get the earliest date. Here's the LINQ query I wrote:
DateTime max = dates.GroupBy(s => s)
.OrderByDescending(s => s.Count())
.ThenBy(s => s)
.First().Key;
Here I'm getting the error:
At least one object must implement IComparable.'
How do I do this?
#Servy is correct.
I would suggest:
DateTime max = dates.GroupBy(s => s)
.OrderByDescending(sg => sg.Count())
.ThenBy(sg => sg.Key)
.First().Key;
You're trying to order by a group of dates. An entire group of dates can't be compared to another group of dates (unless you supply a custom comparer).
You probably want to order on the group's key, which is a single date, not on the entire group.
Related
so I got in C# a String list with a lot of different dates. Now what I want to do is to sort all of these dates to Month. That means, I want for every Month who is represented tho create a single String in this date Format: YYYY0MM.
So that when I got these dates:
01.02.2003
05.02.2003
15.02.2004
24.03.2003
That these Dates in this strings Convertet:
String 1 Value: 2003002
String 2 Value: 2004002
String 3 Value: 2003003
I think the trick is to convert the dates to 1st of each month and then do distinct to remove the duplicates and order by months:
string[] input = { "01.02.2003", "05.02.2003", "15.02.2004", "24.03.2003" };
string[] output = input
.Select(x => DateTime.ParseExact(x, "dd.MM.yyyy", CultureInfo.InvariantCulture)) //parse the strings to dates
.Select(x => x.AddDays(1 - x.Day)) //get first day of each month
.Distinct() //remove the duplicates
.OrderBy(x => x.Month) //order by month
.Select(x => x.ToString("yyyy0MM")).ToArray();
I think this will help you:
var dates = new List<string>() { "01.02.2003", "05.02.2003", "15.02.2004", "24.03.2003"};
var result = new List<string>();
dates.ForEach(dateItem =>
{
DateTime dateValue;
if (DateTime.TryParse(dateItem, out dateValue))
{
result.Add($"{ dateValue.Year}0{dateValue.Month.ToString().PadLeft(2,'0')}");
}
});
After running this code segment "result" variables value will be: {"2003002","2003002","2004002","2003003"}
I have a Message table that has fields namely Creation_Date, Message_Count and Message_Cost. I'm trying to group data by the dates but I want the dates to not repeat and then sum the total number of messages and message cost on each date row.
I've tried using the below expression but that doesn't resolve the issue.
var query = db.Messages
.GroupBy(d => d.Creation_Date)
.OrderBy(d => d.Key)
.Select(g =>
new Report
{
TotalMessagesSent = g.Select(t=>t.Message_Count).Distinct().Sum(),
TotalCost = g.Select(p=>p.Customer_Price).Distinct().Sum(),
DateTime = (DateTime)g.Key
});
What am I doing wrong here?
I'm guessing your Creation_Date includes a timestamp? If so, use d.Creation_Date.Date instead to group by the date component only.
I'm trying to group a list of records by hour and store the number of record for each hour. Here is my code :
DateTime firstTimeStamp = myRecords.DataBaseRecords.First().TimeStamp;
Statistics = myRecords.DataBaseRecords
.GroupBy(x => x.TimeStamp.Hour)
.Select(group => new GraphModel() { Date =firstTimeStamp.AddHours(group.Key), Value = group.Count() })
.ToList();
The problem is that when I'm on the select fuction, I cannot acces to the DateTime anymore so the field group.key contains a value between 0 and 24. I just need to group all the records by hour and foreach hour, I need to have the number of records in the Value parameter.
You have to group the data by absolute hours as of the first timestamp, i.e. the differences in hours calculated for each TimeStamp value:
Statistics = myRecords.DataBaseRecords
.GroupBy(x => DbFunctions.DiffHours(firstTimeStamp, x.TimeStamp) into g
.Select(g => new GraphModel
{
Date = g.FirstOrDefault().TimeStamp,
Value = g.Count()
};
If this is plain LINQ to objects (not Entity Framework) you can replace ...
DbFunctions.DiffHours(firstTimeStamp, x.TimeStamp)
... by
(x.TimeStamp - firstTimeStamp).TotalHours
If it's LINQ to SQL, use
SqlMethods.DateDiffHour(firstTimeStamp, x.TimeStamp)
Perhaps something like this may work out for you:
DateTime myDateTime = new DateTime(DateTime.Parse(firstTimeStamp).AddHours(group.Key).Ticks);
Question specific to answer above:
...Date = new DateTime(DateTime.Parse(firstTimeStamp).AddHours(group.Key))...
If have a directory with files that are created on different dates. I want to get the dates.
Is it possible to do this with a linq query, or must I first read all the files and use a foreach loop to get the dates.
Example:
List =
File_1 6/03/2016
File_2 6/03/2016
File_3 6/03/2016
File_4 6/03/2016
File_5 15/04/2016
File_6 21/04/2016
File_7 21/04/2016
File_8 21/04/2016
Result =
6/03/2016
15/04/2016
21/04/2016
Thanks
Based on the comment from #MatthewWatson.
I have make following linq statement
var dateInfo = Directory.EnumerateFiles(Dir).Select(filename => new FileInfo(filename)).Select(i => new { i.LastWriteTime }).GroupBy(g => g.LastWriteTime.Date);
That way I get all the different dates used in my directory.
Clearly you can't process the list of dates without iterating it, but you can use Linq to produce the sequence in the first place, like so:
var dateInfo =
Directory.EnumerateFiles(directoryName)
.Select(filename => new FileInfo(filename))
.Select(info => new {info.Name, info.CreationTime});
That'll give you a list of FullName/CreationTime pairs, where FullName is the full path of the file, and CreationTime is the creation time of the file.
You can process it like so:
foreach (var item in dateInfo)
Console.WriteLine($"{item.FullName} created on {item.CreationTime}");
If you just want the (unique) dates that the files were created on:
var uniqueDates = dateInfo.GroupBy(x => x.CreationTime.Date).Select(y => y.Key);
foreach (var date in uniqueDates)
Console.WriteLine(date);
Finally, if you need the dates to be ordered:
var uniqueDates =
dateInfo.GroupBy(x => x.CreationTime.Date)
.Select(y => y.Key)
.OrderBy(z => z);
(And use .OrderByDescending() for the reverse order, of course.)
If you prefer Linq query syntax:
var uniqueDates =
from date in dateInfo
group date by date.CreationTime.Date into g
orderby g.Key
select g.Key;
Or putting the entire thing in one Linq query (maybe getting a bit unreadble here, so you might want keep it as separate queries, but this is for completeness):
var uniqueDates =
from date in
from file in Directory.EnumerateFiles(directoryName)
select new FileInfo(file).CreationTime
group date by date.Date into g
orderby g.Key
select g.Key;
I am fetching the attendance details of employees in a datatable .
It looks like this
Day SwipeTime
12/31/2012 11AM
12/31/2012 1PM
12/31/2012 7PM
12/31/2012 8PM
1/1/2012 2PM
1/1/2012 7PM
1/1/2012 8PM
1/2/2012 10AM
1/2/2012 8PM
I need to display the date and totalhours for an employee
where totalhours = lastswipe - firstwipe
my result would look like
Day TotalHours
12/31/2012 9
1/1/2012 6
1/2/2012 12
So i need to find min and max swipes grouped by date.
Please help me write the query
You can use Enumerable.GroupBy to group by date. Then you could create a Dictionary<DateTime,int> where the key is the date and the value are the total-hours for that date:
Dictionary<DateTime,int> dateGroups = table.AsEnumerable()
.GroupBy(r => r.Field<DateTime>("Date").Date)
.Select(g => new{
Date = g.Key,
TotalHours = g.Sum(r =>
DateTime.ParseExact(r.Field<string>("SwipeTime"),
"htt", CultureInfo.InvariantCulture).Hour)
}).ToDictionary(x => x.Date, x => x.TotalHours);
Edit: So, that was the TotalHours of the whole day, now the desired max-min calculation. You also have changed your desired timespan-format to "11:41 AM". Then i would use DateTime.Parse(str).TimeOfDay to get the timespan.
Dictionary<DateTime, int> dateGroups = table.AsEnumerable()
.GroupBy(r => r.Field<DateTime>("Date").Date)
.Select(g => new
{
Date = g.Key,
TotalHours =
(g.Max(r => DateTime.Parse(r.Field<string>("SwipeTime")).TimeOfDay)
- g.Min(r => DateTime.Parse(r.Field<string>("SwipeTime")).TimeOfDay)).Hours
}).ToDictionary(x => x.Date, x => x.TotalHours);
In this answer ordered list of times for day is created to avoid two things - parsing all rows twice, and creating two sets from parsed values to get max and min item. Also I do not parse day before grouping, because same date will have same string value.
var query = from row in table.AsEnumerable()
group row by row.Field<string>("Day") into g
let times = g.Select(r => DateTime.Parse(r.Field<string>("SwipeTime")))
.OrderBy(t => t.TimeOfDay)
.ToList()
select new
{
DateTime.Parse(g.Key).Date,
(times.Last() - times.First()).TotalHours
};
Result is a collection of anonymous objects with two properties DateTime Date and double TotalHours