C# 仅使用LINQ对集合执行计算

C# 仅使用LINQ对集合执行计算,c#,linq,C#,Linq,我只想使用LINQ执行以下操作 我有一个带有用户进出时间的时间表条目列表。该类如下所示: public class TimeSheetLog { public Guid EmployeeId { get; set; } public DateTime ClockInTimeStamp { get; set; } public DateTime ClockOutTimeStamp { get; set; } } 我正在传递一个List(),其中包含年初至今的所有日志 我试图计算

我只想使用LINQ执行以下操作

我有一个带有用户进出时间的时间表条目列表。该类如下所示:

public class TimeSheetLog
{
   public Guid EmployeeId { get; set; }
   public DateTime ClockInTimeStamp { get; set; }
   public DateTime ClockOutTimeStamp { get; set; }
}
我正在传递一个
List()
,其中包含年初至今的所有日志

我试图计算一月份的总工作时间——不管员工是谁。还请注意,我有一个名为
GetTimeDifferenceInMinutes()
的函数,它计算两个日期/时间值之间的分钟数

这是我目前拥有的,但我觉得整个事情只能用LINQ来完成

public static int GetTotalTimeWorked(List<TimeSheetLog> logs, DateTime startDate, DateTime endDate)
{
   // I'm passing 1/1/2018 for startDate and 1/31/2018 for endDate to this function
   var totalTimeWorkedInMinutes = 0;

   var januaryLogs = logs.Where(x => x.ClockInTimeStamp >= startDate && 
   x.ClockOutTimeStamp <= endDate);

   foreach(var item in januaryLogs)
   {
      totalTimeWorkedInMinutes += GetTimeDifferenceInMinutes(item.ClockInTimeStamp, itemClockOutTimeStamp);
   }

   return totalTimeWorkedInMinutes;
}
public static int GetTotalTimeWorked(列出日志、日期时间开始日期、日期时间结束日期)
{
//我将通过2018年1月1日的startDate和2018年1月31日的endDate来完成此功能
var totalTimeWorkedInMinutes=0;
var januaryLogs=logs.Where(x=>x.ClockInTimeStamp>=startDate&&
x、 ClockOutTimeStamp您需要总和

var tot = januaryLogs.Sum(item=>GetTimeDifferenceInMinutes(item.ClockInTimeStamp, itemClockOutTimeStamp));

你不能用求和的方法计算Where,然后在求和中进行DateTime减法,所以

decimal total = logs.Where(x => x.ClockInTimeStamp >= startDate && x.ClockOutTimeStamp <= endDate).Sum(x.ClockOutTimeStamp.Subtract(x.ClockInTimeStamp).TotalMinutes);
decimal total=logs.Where(x=>x.ClockInTimeStamp>=startDate&&x.ClockOutTimeStamp
var logsFilteredByDate=logs.Where(x=>x.ClockInTimeStamp>=startDate)&&
x、 时钟输出时间戳
GetTimeDifferenceInMinutes(x.ClockInTimeStamp,x.ClockOutTimeStamp));
或者,将所有内容合并到一个查询中,这是不必要的,而且更难阅读

var totalTimeWorkedInMinutes = logs.Where(x => x.ClockInTimeStamp >= startDate &&
    x.ClockOutTimeStamp <= endDate)
    .Sum(x => 
        GetTimeDifferenceInMinutes(x.ClockInTimeStamp, x.ClockOutTimeStamp));
var totalTimeWorkedInMinutes=日志。其中(x=>x.ClockInTimeStamp>=开始日期&&
x、 时钟输出时间戳
GetTimeDifferenceInMinutes(x.ClockInTimeStamp,x.ClockOutTimeStamp));

另一个选项是使用
.Aggregate
函数

public static int GetTotalTimeWorked(List<TimeSheetLog> logs, DateTime startDate, DateTime endDate)
{
    var totalTimeWorkedInMinutes = 0;

    return logs.Where(x => x.ClockInTimeStamp >= startDate && x.ClockOutTimeStamp <= endDate)
        .Aggregate(totalTimeWorkedInMinutes, (total, item) => total + GetTimeDifferenceInMinutes(item.ClockInTimeStamp, item.ClockOutTimeStamp));

}
public static int GetTotalTimeWorked(列出日志、日期时间开始日期、日期时间结束日期)
{
var totalTimeWorkedInMinutes=0;
返回日志。其中(x=>x.ClockInTimeStamp>=startDate和&x.ClockOutTimeStamp总计+GetTimeDifferenceInMinutes(item.ClockInTimeStamp,item.ClockOutTimeStamp));
}

除非你意识到时间表可以跨越几个月,否则这个问题似乎很容易解决。因此,如果有人在1月31日打卡,而在2月1日打卡,你必须计算部分时间表才能正确完成

以下是我的解决方案:

public static class ExtensionMethods
{
    static public double TotalMinutes(this IEnumerable<TimeSheetLog> input, DateTime startPeriod, DateTime endPeriod)
    {
        return TimeSpan.FromTicks
        (
            input
            .Where( a=>
                a.ClockOutTimeStamp >= startPeriod &&
                a.ClockInTimeStamp <= endPeriod
            )
            .Select( a=>
                Math.Min(a.ClockOutTimeStamp.Ticks, endPeriod.Ticks) - 
                Math.Max(a.ClockInTimeStamp.Ticks, startPeriod.Ticks)
            )
            .Sum()
        )
        .TotalMinutes;
    }
}
输出:

1320.00
…这是正确的


虽然聚合通常很有用,但Sum方法是一种专门用于计算总和的聚合器。这种方法不包括任何部分与开始日期或结束日期重叠的时间表,因此一些员工显然不会获得全额工资。如果你在1/31从晚上10点开始在墓地工作,你应该在一天内获得两小时的工资1月和2月的剩余时间。@JohnWu我只是回答如何使用已经提供的查询进行LINQ。您所指出的是有效的,但不是问题。问题是如何获取第一个查询的结果并使用LINQ求和。这对OP来说是一个很好的评论,但不在问题的范围之内。
public class Program
{
    static public List<TimeSheetLog> testData = new List<TimeSheetLog>
    {
        new TimeSheetLog
        {
            ClockInTimeStamp = DateTime.Parse("1/1/2018 9:00 am"),
            ClockOutTimeStamp = DateTime.Parse("1/1/2018 5:00 pm")

        },
        new TimeSheetLog
        {
            ClockInTimeStamp = DateTime.Parse("1/2/2018 9:00 am"),
            ClockOutTimeStamp = DateTime.Parse("1/2/2018 5:00 pm")

        },
        new TimeSheetLog
        {
            ClockInTimeStamp = DateTime.Parse("1/31/2018 6:00 pm"),
            ClockOutTimeStamp = DateTime.Parse("2/1/2018 9:00 am")

        },
        new TimeSheetLog
        {
            ClockInTimeStamp = DateTime.Parse("2/3/2018 9:00 am"),
            ClockOutTimeStamp = DateTime.Parse("2/3/2018 5:00 pm")

        }
    };


    public static void Main()
    {
        var startPeriod = new DateTime(2018, 1, 1);
        var endPeriod = new DateTime(2018, 1, 31, 23, 59, 59, 9999); 
        Console.WriteLine( testData.TotalMinutes(startPeriod, endPeriod).ToString("0.00") );
    }
}
1320.00