我想使用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
字段
现在我想要的是计算每位用户 1 的leavedates
个数,并保留类型!= 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
});
}
}
}
}
}
答案 0 :(得分: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});
}
}
}
}
使用该更改,您的代码已经大约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});
}
}
}
}
我们意识到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});
}
}
}
}
我们注意到我们在最终的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});
}
}
}
}
现在,您的代码比以前更容易阅读。继续!将外循环重写为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
辅助方法计算每用户总和。
但同样,这是基于你已经构建了整个机制来计算总和的假设。再次:设计您的代码,以便用该流程的术语清楚地实现业务流程。如果你正在做的就是计算这笔钱,那么,这就是你的原始代码中没有出现的。努力使代码更清晰。
答案 1 :(得分:1)
这基本上是1行linq和groupby,我不确定是不是通过1次尝试得到它,但是有些东西:
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)))
...
答案 2 :(得分:-1)
不是linq版本,而是使用foreach来简化并使其更具可读性
SELECT
ISNULL(COUNT(DTAMID), 0)
FROM
table1
WHERE
LayoutName = RTRIM(LTRIM('layout1'))
AND Content = RTRIM(LTRIM('test221'))
GROUP BY
DTAMID