C# 如何简化嵌套for循环

C# 如何简化嵌套for循环,c#,linq,C#,Linq,我想使用linq使我的代码简短 我有一个包含leaveDates的列表,每个leaveDates都包含leavelist的数量 大概是这样的: { leaves_date = {07-05-2018 18:30:00}, LeaveList = {System.Collections.Generic.List<TimeClock.Model.LeaveManagementModel>} } { leaves_date = {08-05-2018 18:30:00}, LeaveLis

我想使用linq使我的代码简短

我有一个包含
leaveDates
的列表,每个
leaveDates
都包含
leavelist
的数量

大概是这样的:

{ leaves_date = {07-05-2018 18:30:00}, LeaveList = {System.Collections.Generic.List<TimeClock.Model.LeaveManagementModel>} }
{ leaves_date = {08-05-2018 18:30:00}, LeaveList = {System.Collections.Generic.List<TimeClock.Model.LeaveManagementModel>} }
{ leaves_date = {21-05-2018 18:30:00}, LeaveList = {System.Collections.Generic.List<TimeClock.Model.LeaveManagementModel>} }

这基本上是一行linq和一个groupby,我不确定我会用一次尝试就成功,但大致如下:

var attendancelist = leavesresult
               .SelectMany(a => a.LeaveList) // flatten the list
               .Where(a => a.status == "1" && a.type != "3") // pick the right items 
               .GroupBy(a => a.user_id) // group by users
               .Select(g => new AttendanceModel(){ // project the model
                    user_id = g.Key,
                    days = g.Aggregate(0, (a,b) => a + (b.check_halfday == 1 ? 0.5 : 1))
               })
               .ToList();
让我知道任何问题,我会在必要时设法解决


edit1:假设
AttendanceModel.days
是一个
int
,在计算浮点值时,您需要决定要做什么

也许是这样的:

...
days = (int)Math.Ceiling(g.Aggregate(0, (a,b) => a + (b.check_halfday == 1 ? 0.5 : 1)))
...

我可以向你提问,你什么也学不到。相反,自己学习如何进行此转换。诀窍是不要试图一次做完所有的事情。相反,我们做了一系列小的、明显正确的转换,每一个都让我们更接近我们的目标

首先,将for的内部
循环重写为foreach

for (var i = 0; i < leavesresult.Count; i++) 
{
  foreach (var leavelist in leavesresult[i].LeaveList) 
  {
    if (leavelist.status == 1.ToString() && leavelist.leave_type != 3.ToString()) 
    {
      var compair1 = leavelist.user_id;
      var compair2 = attendancelist.Any(z => z.user_id == leavelist.user_id);
      if (attendancelist.Any(z => z.user_id == leavelist.user_id)) 
      {
        int index = attendancelist.FindIndex(y => y.user_id == leavelist.user_id);  
        if (leavelist.check_halfday == 1) 
          attendancelist[index].days = attendancelist[index].days
        else 
          attendancelist[index].days = attendancelist[index].days + 1;
      }
      else 
      {
        if (leavelist.check_halfday == 1) 
          attendancelist.Add(
            new AttendanceModel {user_id = leavelist.user_id, days = 0.5});
        else 
          attendancelist.Add(
            new AttendanceModel {user_id = leavelist.user_id, days = 1});
      }
    }
  }
}
foreach (var lr in leavesresult) 
{
  foreach (var leavelist in lr.LeaveList) 
  {
    if (leavelist.status == "1" && leavelist.leave_type != "3") 
    {
      var user_id = leavelist.user_id;
      int index = attendancelist.FindIndex(y => y.user_id == user_id);
      if (index != -1) 
      {
        if (leavelist.check_halfday != 1) 
          attendancelist[index].days = attendancelist[index].days + 1;
      }
      else 
      {
        double days = leavelist.check_halfday == 1 ? 0.5 : 1;
        attendancelist.Add(new AttendanceModel {user_id = user_id, days = days});
      }
    }
  }
}
这是一个疯狂的方式写这张支票。把它改写成一张合理的支票

      var compair1 = leavelist.user_id;
      var compair2 = attendancelist.Any(z => z.user_id == leavelist.user_id);
这两个变量都不会被读取,它们的初始值设定项也没用。删除第二个。将第一个重命名为
user\u id

        if (leavelist.check_halfday == 1) 
          attendancelist[index].days = attendancelist[index].days
        else 
          attendancelist[index].days = attendancelist[index].days + 1;
结果毫无意义。重写这个

好的,我们现在有

for (var i = 0; i < leavesresult.Count; i++) 
{
  foreach (var leavelist in leavesresult[i].LeaveList) 
  {
    if (leavelist.status == "1" && leavelist.leave_type != "3") 
    {
      var user_id= leavelist.user_id;
      if (attendancelist.Any(z => z.user_id == leavelist.user_id)) 
      {
        int index = attendancelist.FindIndex(y => y.user_id == leavelist.user_id);  
        if (leavelist.check_halfday != 1) 
          attendancelist[index].days = attendancelist[index].days + 1;
      }
      else 
      {
        if (leavelist.check_halfday == 1) 
          attendancelist.Add(
            new AttendanceModel {user_id = leavelist.user_id, days = 0.5});
        else 
          attendancelist.Add(
            new AttendanceModel {user_id = leavelist.user_id, days = 1});
      }
    }
  }
}
我们注意到在最后的
if-else
中复制了代码。唯一的区别是
天数

for (var i = 0; i < leavesresult.Count; i++) 
{
  foreach (var leavelist in leavesresult[i].LeaveList) 
  {
    if (leavelist.status == "1" && leavelist.leave_type != "3") 
    {
      var user_id = leavelist.user_id;
      int index = attendancelist.FindIndex(y => y.user_id == user_id);
      if (index != -1) 
      {
        if (leavelist.check_halfday != 1) 
          attendancelist[index].days = attendancelist[index].days + 1;
      }
      else 
      {
        double days = leavelist.check_halfday == 1 ? 0.5 : 1;
        attendancelist.Add(new AttendanceModel {user_id = user_id, days = days});
      }
    }
  }
}
我们还注意到了一些事情:我们可以将
check\u halfday
放入解释变量中,并消除
天数。我们可以简化增量:

foreach (var lr in leavesresult) 
{
  foreach (var leavelist in lr.LeaveList) 
  {
    if (leavelist.status == "1" && leavelist.leave_type != "3") 
    {
      var user_id = leavelist.user_id;
      int index = attendancelist.FindIndex(y => y.user_id == user_id);
      bool halfday= leavelist.check_halfday == 1;
      if (index != -1) 
      {
        if (!halfday) 
          attendancelist[index].days += 1;
      }
      else 
      {
        attendancelist.Add(new AttendanceModel {user_id = user_id, days = halfday ? 0.5 : 1});
      }
    }
  }
}
现在我们开始将其转换为查询。要理解的关键是,突变不能出现在查询中。突变只会进入循环,而不会进入查询。查询询问问题,但不执行突变

您有一个
attendancelist
的变异,因此必须保持循环。但我们可以通过识别内部循环中带有测试的嵌套foreach等价于:

var query = from lr in leaveresult
            from ll in lr.LeaveList
            where ll.status == "1"
            where ll.leave_type != "3"
            select ll;
好极了。现在我们可以在foreach中使用它:

foreach(var ll in query) 
{
  var index = attendancelist.FindIndex(y => y.user_id == ll.user_id);
  var halfday = ll.check_halfday == 1;
  if (index != -1) 
  {
    if (!halfday) 
      attendancelist[index].days += 1;
  }
  else 
  {
    attendancelist.Add(
      new AttendanceModel {user_id = ll.user_id, days = halfday? 0.5 : 1 });
  }
}
现在我们有了这个非常简单的循环形式,我们注意到我们可以对
if
重新排序以简化它:

foreach(var ll in query) 
{
  var index = attendancelist.FindIndex(y => y.user_id == ll.user_id);
  var halfday = ll.check_halfday == 1;
  if (index == -1) 
    attendancelist.Add(
      new AttendanceModel {user_id = ll.user_id, days = halfday? 0.5 : 1 });
  else if (!halfday) 
    attendancelist[index].days += 1;
}
我们完成了。所有的计算都是由查询完成的,所有的突变都是由foreach完成的。循环体现在是一个非常清晰的条件语句


这个答案是为了回答您的问题,即如何将现有的一组难以阅读的循环转换为易于阅读的查询。但最好还是编写一个查询,清楚地表达您试图实现的业务逻辑,我不知道这是什么创建您的LINQ查询,使其易于理解业务级别发生的事情

在这种情况下,我怀疑您正在维护每个用户的天数计数,并根据休假列表进行更新。让我们来写吧

// dict[user_id] is the accumulated leave.
var dict = new Dictionary<int, double>();
var query = from lr in leaveresult
            from ll in lr.LeaveList
            where ll.status == "1"
            where ll.leave_type != "3"
            select ll;
foreach(var ll in query) 
{
  var halfday = ll.check_halfday == 1;
  if (!dict.ContainsKey(ll.user_id)) 
    dict[ll.user_id] = halfday? 0.5 : 1;
  else if (!halfday) 
    dict[ll.user_id] = dict[ll.user_id] + 1;
}
//dict[user\u id]是累计假期。
var dict=新字典();
var query=来自leaveresult中的lr
从左列表中的ll开始
其中ll.status==“1”
ll.LEVE_类型的位置!="3"
选择ll;
foreach(查询中的变量ll)
{
var半天=ll.check_半天=1;
如果(!dict.ContainsKey(ll.user_id))
dict[ll.user_id]=半天?0.5:1;
否则,如果(!半天)
dict[ll.user\u id]=dict[ll.user\u id]+1;
}
这似乎是一个更好的方式来表示这一点,而不是一个列表,你必须不断地搜索

一旦我们到了这一点,我们就可以认识到,您真正做的是计算每个用户的总和!JamieC的答案表明,您可以使用
Aggregate
helper方法来计算每个用户的总和


但同样,这是基于这样的假设,即你已经建立了整个机制来计算这个总和。同样:设计代码,使其能够用流程的术语清楚地实现业务流程。如果你所做的是计算那个总和,孩子,那在你的原始代码中就不会出现。努力使代码更清晰。不是linq版本,而是使用foreach来简化和提高可读性

    var userLeaves = new Dictionary<int, double>();
    foreach( var lr in leavesresult)
    {
        foreach (var leave in lr.LeaveList) 
        {
            if (leave.Status == "1" && leave.LeaveType != "3") 
            {
                var leaveDay = leave.check_halfday ==1 ? 0.5 : 1;
                if (userLeaves.ContainsKey(leave.UserID))
                    userLeaves[leave.UserID] = userLeaves[leave.UserID] + leaveDay;
                else
                    userLeaves.Add(leave.UserID, leaveDay);
            }
        }
    }
var userLeaves=newdictionary();
foreach(leavesresult中的var lr)
{
foreach(左离开列表中的var离开)
{
如果(leave.Status==“1”和&leave.LeaveType!=“3”)
{
var leaveDay=休假。检查_半天==1?0.5:1;
if(userLeaves.ContainsKey(leave.UserID))
userLeaves[leave.UserID]=userLeaves[leave.UserID]+leaveDay;
其他的
添加(leave.UserID,leaveDay);
}
}
}

您尝试过任何LINQ查询吗?尝试过但没有succeed@ChitraNandpal请告诉我们你试过什么。在问题中,而不是在注释中。步骤1,如果您不介意,IMO将把嵌套分解为单独的逻辑调用。这样,每个调用都有自己的目的,使代码更具可读性。单独做这件事通常会让你了解如何立即简化它。它还使转换为linq或以后编辑变得更容易,而不会中断迭代的步骤。我个人的目标是,在编写任何嵌套代码时,确保boiler plate逻辑在单个方法中仅作为一个循环流入。确保每个方法都有相应的名称,并在有意义时使用本地方法。对这个问题进行投票,唯一的原因是Eric Lippert写的最关心的答案。我没有像天数这样的字段,我想计算休假日期的天数vise@ChitraNandpal我的错,我误读了那一点。请参阅更新-这是否更接近您正在尝试执行的操作?此处检查_halfday为int,因此如果值==1,则最后一个问题是0.5或1,它给出了错误,如无法转换双i
foreach(var ll in query) 
{
  var index = attendancelist.FindIndex(y => y.user_id == ll.user_id);
  var halfday = ll.check_halfday == 1;
  if (index != -1) 
  {
    if (!halfday) 
      attendancelist[index].days += 1;
  }
  else 
  {
    attendancelist.Add(
      new AttendanceModel {user_id = ll.user_id, days = halfday? 0.5 : 1 });
  }
}
foreach(var ll in query) 
{
  var index = attendancelist.FindIndex(y => y.user_id == ll.user_id);
  var halfday = ll.check_halfday == 1;
  if (index == -1) 
    attendancelist.Add(
      new AttendanceModel {user_id = ll.user_id, days = halfday? 0.5 : 1 });
  else if (!halfday) 
    attendancelist[index].days += 1;
}
// dict[user_id] is the accumulated leave.
var dict = new Dictionary<int, double>();
var query = from lr in leaveresult
            from ll in lr.LeaveList
            where ll.status == "1"
            where ll.leave_type != "3"
            select ll;
foreach(var ll in query) 
{
  var halfday = ll.check_halfday == 1;
  if (!dict.ContainsKey(ll.user_id)) 
    dict[ll.user_id] = halfday? 0.5 : 1;
  else if (!halfday) 
    dict[ll.user_id] = dict[ll.user_id] + 1;
}
    var userLeaves = new Dictionary<int, double>();
    foreach( var lr in leavesresult)
    {
        foreach (var leave in lr.LeaveList) 
        {
            if (leave.Status == "1" && leave.LeaveType != "3") 
            {
                var leaveDay = leave.check_halfday ==1 ? 0.5 : 1;
                if (userLeaves.ContainsKey(leave.UserID))
                    userLeaves[leave.UserID] = userLeaves[leave.UserID] + leaveDay;
                else
                    userLeaves.Add(leave.UserID, leaveDay);
            }
        }
    }