c# - 如何简化我的嵌套 for 循环
问题描述
我想使用 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>} }
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
});
}
}
}
}
}
解决方案
我可以给你查询,你什么也学不到。而是学习如何自己进行这种转变。诀窍是不要尝试一次完成所有操作。相反,我们进行了一系列小的、明显正确的转换,每一个都让我们更接近我们的目标。
首先将内部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});
}
}
}
}
通过该更改,您的代码已经比阅读更容易了 100 倍。
现在我们注意到一些事情:
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);
这些变量都不会被读取,并且它们的初始化器是无用的。删除第二个。将第一个重命名为user_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});
}
}
}
}
在整个过程中使用辅助变量:
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});
}
}
}
}
我们意识到 theAny
和 theFindIndex
正在做同样的事情。消除其中之一:
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});
}
}
}
}
我们注意到我们在 final 中复制了代码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});
}
}
}
}
现在,您的代码比以前容易阅读 1000 倍。继续!将外循环重写为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});
}
}
}
}
我们注意到更多的事情:我们可以放入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});
}
}
}
}
现在我们开始将其转换为查询。要理解的关键是突变不能进入查询。突变只进入循环,从不查询。查询提出问题,它们不执行突变。
你有一个 的突变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;
}
这似乎是一种比您不断搜索的列表更好的表示方式。
一旦我们达到这一点,我们就可以认识到您真正在做的是计算每个用户的总和!JamieC 的回答表明您可以使用Aggregate
辅助方法来计算每个用户的总和。
但同样,这是基于您已经构建了整个机制来计算该总和的假设。再次:设计您的代码,使其清楚地按照该流程的行话实现业务流程。如果你正在做的是计算那个总和,男孩,那会不会出现在你的原始代码中。努力让你的代码在做什么更清楚。
推荐阅读
- django - Queryset Django - 根据重量隔间中的参数日期
- python - AttributeError: dense_prediction_cell_json - 为什么无法加载json文件?
- javascript - 方法 window.top.postMessage 重定向到初始页面
- c# - 如何检查 MethodInfo 是否是特定的接口方法
- php - PHP替换公式中的特定值
- mysql - 如何使用 Linux 和 MariaDB 将数据导入或导出到另一台服务器
- java - 键为空时处理 Firebase 通知远程消息
- codenameone - 如何创建包含 Switch 组件的列表
- php - 在 wordpress 中添加自定义 rest api 支持时要编辑哪个文件
- android - 如何使用 AWS/GCP 在 Android 应用程序上设置直播?