LinQ查询中的lambda表达式中的C#多变量

时间:2017-05-10 14:30:34

标签: c# linq lambda

我正在使用由班次组成的护士日历:

public interface IShift
{
    ShiftType ShiftType { get; } //enum {Day, Early, Late, Night}
    DateTime Day { get; }
    bool IsNightShift();
    bool IsWeekendShift();
}

护士日历为IEnumerable<IShift>。从那时起,我选择自己的班次(IEnumerable<IShift> selectedShifts)一段较短的时间来检查一些限制。

我正在尝试计算多个条件,例如星期五的夜班:

var countFridayNight = selectedShifts.Count(s => s.IsNightShift() 
    && s.Day.DayOfWeek == DayOfWeek.Friday);

我正在努力的是在多天内计算多件事。例如,周五晚班和下周一早班。 我试过这个,但VS似乎不喜欢语法:

var countFridayLateAndMondayEarly =
                    selectedShifts.Count(
                        (r, s) =>  s.ShiftType == ShiftType.Late && s.Day.DayOfWeek == DayOfWeek.Friday 
                            && r.Day.DayOfWeek == DayOfWeek.Monday && r.Day.AddDays(-2).DayOfYear == s.Day.DayOfYear && r.ShiftType == ShiftType.Early
                            );

编辑:删除最后一个lambda表达式中的花括号。

Edit2:有两条评论说Count不能在lambda表达式中使用多个变量。我怎样才能做到使用LINQ所需要的东西?

编辑3:问题的澄清 - 我需要计算周五晚班制的变化,同时还有另一个变化,即下周一早些时候。

6 个答案:

答案 0 :(得分:5)

为了解决这个问题,你需要将集合交叉连接到自身 - 基本上你需要获得每个的移位组合并计算,其中第一个是星期五晚上,第二个星期一早上。

首先得到对:

import zipfile, re, os

def extract_nested_zip(zippedFile, toFolder):
    """ Extract a zip file including any nested zip files
        Delete the zip file(s) after extraction
    """
    with zipfile.ZipFile(zippedFile, 'r') as zfile:
        zfile.extractall(path=toFolder)
    os.remove(zippedFile)
    for root, dirs, files in os.walk(toFolder):
        for filename in files:
            if re.search(r'\.zip$', filename):
                fileSpec = os.path.join(root, filename)
                extract_nested_zip(fileSpec, root)

其次,计算符合条件的对:

var pairs = selectedShifts.SelectMany(s => selectedShifts, Tuple.Create);

如果轮班已按顺序排序,您可以更有效地获得对,并且想要计算相邻轮班:

var count = pairs.Count(pair => 
       pair.Item1.ShiftType == ShiftType.Late 
    && pair.Item1.Day.DayOfWeek == DayOfWeek.Friday 
    && pair.Item2.Day.DayOfWeek == DayOfWeek.Monday 
    && pair.Item2.Day.AddDays(-2).DayOfYear == pair.Item1.Day.DayOfYear 
    && pair.Item2.ShiftType == ShiftType.Early);

答案 1 :(得分:3)

如果你在配对之前减少对lateFridays和earlyMondays的输入,它应该会更快一点。

var lateFridays = selectedShifts
  .Where(s => s.ShiftType == ShiftType.Late && s.Day.DayOfWeek == DayOfWeek.Friday)
  .ToList();

var earlyMondays = selectedShifts
  .Where(r => r.Day.DayOfWeek == DayOfWeek.Monday && r.ShiftType == ShiftType.Early)
  .ToList();

var matchingPairs = lateFridays.SelectMany(friday => earlyMondays, Tuple.Create)
  .Where(t => t.Item2.Day.AddDays(-2).DayOfYear == t.Item1.Day.DayOfYear);

var count = matchingPairs.Count();

此外,这个日期比较对于跨年案例也不好。

答案 2 :(得分:1)

严格地说,你可以使用类似的东西:

    var cnt = selectedShifts.Count(shift =>
            shift.Day.DayOfWeek == DayOfWeek.Friday && shift.ShiftType==ShiftType.Late
                && selectedShifts.Any(next =>next.Day == shift.Day.AddDays(3) && next.ShiftType == ShiftType.Early)
    );

但是在性能方面,通过将它们链接在一起或与子列表相关联来确定下一个班次可能会更好。例如:

    var lst= selectedShifts.ToList(); //Assuming already ordered, otherwise add an 'OrderBy' before the 'ToList'
    var cnt = lst.Where((shift,index)=> shift.Day.DayOfWeek == DayOfWeek.Friday && shift.ShiftType==ShiftType.Late 
        && index < lst.Count-1 && lst[index+1].Day == shift.Day.AddDays(3) && lst[index+1].ShiftType == ShiftType.Early);

后者假设下一班次是周一班次而不是周末轮班。使用最后一种方法,您还可以检查延迟班次和下一班次之间的天数(或小时数)是否小于&#39; x&#39;量

答案 3 :(得分:0)

如果我正确阅读了问题,您只需要OR语法。这将分别在星期一和星期一早些时候提供延迟班次:

var countFridayLateAndMondayEarly =
                    selectedShifts.Count(
                        shift => (shift.ShiftType == ShiftType.Late && shift.Day.DayOfWeek == DayOfWeek.Friday)
|| // or 
                            (shift.Day.DayOfWeek == DayOfWeek.Monday && shift.ShiftType == ShiftType.Early
                            ));

答案 4 :(得分:0)

如果你喜欢真正的Linq语法,你可以这样做。

    var matchingPairs = from lateFriday in
                             (from r in selectedShifts where r.Day.DayOfWeek == DayOfWeek.Monday && r.ShiftType == ShiftType.Early select r)
                        from earlyMonday in
                             (from s in selectedShifts where s.Day.DayOfWeek == DayOfWeek.Monday && s.ShiftType == ShiftType.Early select s)
                        where earlyMonday.Day.AddDays(-2).DayOfYear == lateFriday.Day.DayOfYear
                        select new { lateFriday, earlyMonday };

var count = matchingPairs.Count();

答案 5 :(得分:0)

另一种变体 它不会比交叉连接更好地执行,因为它做同样的事情但可能更具可读性。 只在内存中的列表上使用它。

selectedShifts.Where(x => x.Day.DayOfWeek == DayOfWeek.Friday && x.ShiftType == ShiftType.Late && 
  list.Any(y => x.Day.AddDays(3) == y.Day && y.ShiftType == ShiftType.Early))