如何简化嵌套for循环

Chi*_*pal 0 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}, LeaveList = {System.Collections.Generic.List<TimeClock.Model.LeaveManagementModel>} }
{ leaves_date = {21-05-2018 18:30:00}, LeaveList = {System.Collections.Generic.List<TimeClock.Model.LeaveManagementModel>} }
Run Code Online (Sandbox Code Playgroud)

leaveList包括UserId,LeaveType,Status领域

现在我想要的是计算leavedates状态为1的每个用户的数量并保留类型!= 3

我已经尝试过使用for循环,但我想用linq来做.

这是我的代码与for循环:

for (var i = 0; i < leavesresult.Count; i++) {
    for (var a = 0; a < leavesresult[i].LeaveList.Count; a++) {
        if (leavesresult[i].LeaveList[a].status == 1.ToString() && leavesresult[i].LeaveList[a].leave_type != 3.ToString()) {
            var compair1 = leavesresult[i].LeaveList[a].user_id;
            var compair2 = attendancelist.Any(z = >z.user_id == leavesresult[i].LeaveList[a].user_id);

            if (attendancelist.Any(z = >z.user_id == leavesresult[i].LeaveList[a].user_id)) {
                int index = attendancelist.FindIndex(y = >y.user_id == leavesresult[i].LeaveList[a].user_id);

                if (leavesresult[i].LeaveList[a].check_halfday == 1) {
                    attendancelist[index].days = attendancelist[index].days
                }
                else {
                    attendancelist[index].days = attendancelist[index].days + 1;
                }
            }
            else {
                if (leavesresult[i].LeaveList[a].check_halfday == 1) {
                    attendancelist.Add(new AttendanceModel {
                        user_id = leavesresult[i].LeaveList[a].user_id,
                        days = 0.5
                    });
                }
                else {
                    attendancelist.Add(new AttendanceModel {
                        user_id = leavesresult[i].LeaveList[a].user_id,
                        days = 1
                    });
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Eri*_*ert 17

我可以给你查询,你什么都不会学到.而是自己学习如何进行这种转变.诀窍是不要试图一次完成所有操作.相反,我们制作了一系列小的,明显正确的变换,每个变换都让我们更接近目标.

首先将内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});
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

使用该更改,您的代码已经大约100倍易于阅读.

现在我们注意到一些事情:

    if (leavelist.status == 1.ToString() && leavelist.leave_type != 3.ToString()) 
Run Code Online (Sandbox Code Playgroud)

这是写这个检查的疯狂方式.将其重写为合理的检查.

      var compair1 = leavelist.user_id;
      var compair2 = attendancelist.Any(z => z.user_id == leavelist.user_id);
Run Code Online (Sandbox Code Playgroud)

这些变量都没有读过,它们的初始化器也没用.删除第二个.将第一个重命名为user_id.

        if (leavelist.check_halfday == 1) 
          attendancelist[index].days = attendancelist[index].days
        else 
          attendancelist[index].days = attendancelist[index].days + 1;
Run Code Online (Sandbox Code Playgroud)

结果毫无意义.改写这个.

好的,我们现在有

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});
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

在整个过程中使用辅助变量:

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 == user_id)) 
      {
        int index = attendancelist.FindIndex(y => y.user_id == 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 = user_id, days = 0.5});
        else 
          attendancelist.Add(
            new AttendanceModel {user_id = user_id, days = 1});
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

我们意识到Any并且FindIndex正在做同样的事情.消除其中一个:

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 
      {
        if (leavelist.check_halfday == 1) 
          attendancelist.Add(
            new AttendanceModel {user_id = user_id, days = 0.5});
        else 
          attendancelist.Add(
            new AttendanceModel {user_id = user_id, days = 1});
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

我们注意到我们正在复制最终的代码if-else.唯一的区别是days:

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});
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

现在,您的代码比以前更容易阅读.继续!将外循环重写为foreach:

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});
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

我们还注意到了更多的事情:我们可以将check_halfday解释变量放入,并消除days.我们可以简化增量:

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});
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

现在我们开始将其转换为查询.要理解的关键是突变不能进入查询.突变只进入循环,从不进行查询.查询提问,他们不执行突变.

你有一个突变attendancelist,所以必须保持循环.但是我们可以通过识别内部循环中带有测试的嵌套foreach等效于以下内容,将所有查询逻辑移出循环:

var query = from lr in leaveresult
            from ll in lr.LeaveList
            where ll.status == "1"
            where ll.leave_type != "3"
            select ll;
Run Code Online (Sandbox Code Playgroud)

优秀.现在我们可以在我们的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 });
  }
}
Run Code Online (Sandbox Code Playgroud)

现在我们以这种非常简单的形式得到循环,我们注意到我们可以重新排序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;
}
Run Code Online (Sandbox Code Playgroud)

我们已经完成了.所有的计算都是由查询完成的,所有的突变都是由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;
}
Run Code Online (Sandbox Code Playgroud)

这似乎是一种更好的方式来代表这个,而不是你经常需要搜索的列表.

一旦我们处于这一点,我们就可以认识到你真正在做的是计算每用户总和!JamieC的答案表明,您可以使用Aggregate辅助方法计算每用户总和.

但同样,这是基于您已经构建了整个机制来计算总和的假设.再次:设计您的代码,以便以该流程的术语清楚地实现业务流程.如果你正在做的是计算这笔钱,那么,那个,你的原始代码中是否会出现这种情况.努力使您的代码更清晰.