C# 如何简化嵌套for循环
我想使用linq使我的代码简短 我有一个包含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
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);
}
}
}