繁体   English   中英

总结一个月的工作时间 - c# & LINQ

[英]Summing hours worked for a week, over the month - c# & LINQ

我想知道如何简化我的查询,因为我知道我正在执行不好的做法并且在事情上走了很长一段路。

基本上,我每周都会将轮班输入到应用程序中,并且我正在计算每周的工作时间。 我想知道如何根据已输入应用程序 (ShiftDate) 的已知班次获取一周的开始日期和一周的结束日期。

下面是 4 周的快速示例,其中我使用 moment.js 计算出一周的开始和结束,并将它们传递给 c# 函数(由 vStart、vEnd 等表示)。

我正在努力如何获得包含 x.ShiftDate 的一周的开始和结束

Week1 = pg.Sum(x => x.ShiftDate >= vStart1 && x.ShiftDate <= vEnd1 ? x.HoursWorked : 0),
Week2 = pg.Sum(x => x.ShiftDate >= vStart2 && x.ShiftDate <= vEnd2 ? x.HoursWorked : 0),
Week3 = pg.Sum(x => x.ShiftDate >= vStart3 && x.ShiftDate <= vEnd3 ? x.HoursWorked : 0),
Week4 = pg.Sum(x => x.ShiftDate >= vStart4 && x.ShiftDate <= vEnd4 ? x.HoursWorked : 0),

我想弄清楚如何只编写一次 sum 函数,而不必在一个月内每周重复

如果没有您的类数据对象代码,这就是我想出的:

namespace ShiftWork
{
    public class UnitTest1
    {
        [Fact]
        public void Test1()
        {
            DateTime vStart1 = DateTime.Now;
            DateTime vEnd1 = vStart1.AddDays(6);
            DateTime vStart2 = vEnd1.AddDays(1);
            DateTime vEnd2 = vStart2.AddDays(6);
            DateTime vStart3 = vEnd2.AddDays(1);
            DateTime vEnd3 = vStart3.AddDays(6);
            DateTime vStart4 = vEnd3.AddDays(1);
            DateTime vEnd4 = vStart4.AddDays(6);

            var startAndEnd = new List<Tuple<DateTime, DateTime>>();
            startAndEnd.Add(new Tuple<DateTime, DateTime>(vStart1, vEnd1));
            startAndEnd.Add(new Tuple<DateTime, DateTime>(vStart2, vEnd2));
            startAndEnd.Add(new Tuple<DateTime, DateTime>(vStart3, vEnd3));
            startAndEnd.Add(new Tuple<DateTime, DateTime>(vStart4, vEnd4));

            var pg = new List<Data>();
            pg.Add(new Data() { ShiftDate = vStart1, HoursWorked = 1 });
            pg.Add(new Data() { ShiftDate = vStart2, HoursWorked = 3 });
            pg.Add(new Data() { ShiftDate = vStart3, HoursWorked = 5 });
            pg.Add(new Data() { ShiftDate = vStart3, HoursWorked = 7 });

            var Week1 = pg.Sum(x => x.ShiftDate >= vStart1 && x.ShiftDate <= vEnd1 ? x.HoursWorked : 0);
            var Week2 = pg.Sum(x => x.ShiftDate >= vStart2 && x.ShiftDate <= vEnd2 ? x.HoursWorked : 0);
            var Week3 = pg.Sum(x => x.ShiftDate >= vStart3 && x.ShiftDate <= vEnd3 ? x.HoursWorked : 0);
            var Week4 = pg.Sum(x => x.ShiftDate >= vStart4 && x.ShiftDate <= vEnd4 ? x.HoursWorked : 0);

            var hoursWorked = pg.Where(x => startAndEnd.Any(dates => dates.Item1 <= x.ShiftDate && dates.Item2 >= x.ShiftDate)).Sum(x => x.HoursWorked);

            Assert.Equal(16,hoursWorked);

            // delete the first week from criteria
            startAndEnd.Remove(startAndEnd.First());

            hoursWorked = pg.Where(x => startAndEnd.Any(dates => dates.Item1 <= x.ShiftDate && dates.Item2 >= x.ShiftDate)).Sum(x => x.HoursWorked);

            // should be 15 because week one deleted
            Assert.Equal(15, hoursWorked);

        }
    }

    public class Data
    {
        public DateTime ShiftDate { get; set; }
        public decimal HoursWorked { get; set; }
    }
}

首先,我建议将 sum 运算中的三元运算符替换为 filter + sum 运算:

  • 替换.Sum( ? : )
.Sum(x => x.ShiftDate >= vStart* && x.ShiftDate <= vEnd* ? x.HoursWorked : 0)
  • .Where( ).Sum( )
.Where(x => x.ShiftDate >= vStart* && x.ShiftDate <= vEnd*)
.Sum(x => x.HoursWorked)

.Sum()如果集合为空,则返回0


避免代码重复的一种选择是创建一个扩展方法来处理过滤+求和:

public static int GetHoursWorked<PgClass>(this IEnumerable<PgClass> source,
    DateTime start, DateTime end)
{
    return source
        .Where(x => x.ShiftDate >= start && x.ShiftDate <= end)
        .Sum(x => x.HoursWorked);
}

并按如下方式调用它:

var week1 = pg.GetHoursWorked(vStart1, vEnd1);
var week2 = pg.GetHoursWorked(vStart2, vEnd2);

在上面的例子中,我假设pg是类PgClass的一些集合,例如List<PgClass>

可能进一步改进的想法:
如果您在一个列表中收集所有关联的vStart*vEnd*值,您可以为该列表中的每个对象选择pg.GetHoursWorked() ,例如创建一个字典,其中周数是键,工作时间是值。

你可以这样做:

var weeklyHours = 
from data in SomeList
group t by new { WeekNumber = (t.SomeTargetDate - firstDay).Days / 7} into weeks
select new
{
    WeekNumber = weeks.Key.WeekNumber,
    Minutes = weeks.Sum(t => t.Minutes)  // here your logic of how minutes are calculated can come
};

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM