我们有以下定义LINQ:
myList.Select(s=> new DtoTest()
{
TotalSamples = myList.Count(c=> c.UserId == s.UserId),
EvaluatedSamples = myList.Count(c=> c.UserId == s.UserId && c.Status == Status.OK)
PercentageRealized = (myList.Count(c=> c.UserId == s.UserId) / myList.Count(c=> c.UserId == s.UserId && c.Status == Status.OK)) * 100
});
有没有一种方法可以在不使用之前在"TotalSamples“和"EvaluatedSamples”中使用的相同函数的情况下分配属性值"PercentageRealized“?
就像这样:
myList.Select(s=> new DtoTest()
{
TotalSamples = myList.Count(c=> c.UserId == s.UserId),
EvaluatedSamples = myList.Count(c=> c.UserId == s.UserId && c.Status == Status.OK)
PercentageRealized = (TotalSamples / EvaluatedSamples) * 100 //<-!Not possible!
});
还有其他建议吗?
发布于 2018-12-13 05:44:30
对我来说,您所做的似乎非常有问题--您正在对源数据进行多次遍历,以一遍又一遍地重新计算相同的东西(每次出现UserId
),而实际上您应该希望的是对每个UserId
计算一次,如下所示:
var ans2 = myList.GroupBy(s => s.UserId)
.Select(sg => {
var ts = sg.Count();
var es = sg.Count(c => c.Status == Status.OK);
return new DtoTest { UserId = sg.Key, TotalSamples = ts, EvaluatedSamples = es, PercentageRealized = (int)(100.0 * ts / es) };
});
此外,除非您首先转换为double
,否则您的百分比计算将使用C#整数除法,并且不会接近正确。完成数学运算后,您可以重新转换为int
。
如果你真的想要返回多个结果,并且想要高效(因为我喜欢扩展方法),那么创建一个扩展方法来计算一次遍历的链式谓词:
public static class IEnumerableExt {
public static (int Cond1Count, int Cond2Count) Count2Chained<T>(this IEnumerable<T> src, Func<T, bool> cond1, Func<T, bool> cond2) {
int cond1Count = 0;
int cond2Count = 0;
foreach (var s in src) {
if (cond1(s)) {
++cond1Count;
if (cond2(s))
++cond2Count;
}
}
return (cond1Count, cond2Count);
}
}
现在,您可以在一次遍历中计算子值并计算第三个值:
var ans3 = myList.Select(s => {
var (ts, es) = myList.Count2Chained(c => c.UserId == s.UserId, c => c.Status == Status.OK);
return new DtoTest { UserId = s.UserId, TotalSamples = ts, EvaluatedSamples = es, PercentageRealized = (int)(100.0 * ts / es) };
});
当然,根据myList
的大小,计算每个答案一次,然后重复一次作为最终答案可能会更好:
var ansd = myList.GroupBy(s => s.UserId)
.Select(sg => {
var ts = sg.Count();
var es = sg.Count(c => c.Status == Status.OK);
return new { sg.Key, ts, es };
})
.ToDictionary(ste => ste.Key, ste => new DtoTest {
UserId = ste.Key,
TotalSamples = ste.ts,
EvaluatedSamples = ste.es,
PercentageRealized = (int)(100.0 * ste.ts / ste.es) });
var ans4 = myList.Select(s => ansd[s.UserId]);
发布于 2018-12-13 05:11:26
更改函数委托以使用已计算的值
myList.Select(s => {
var result = new DtoTest() {
TotalSamples = myList.Count(c => c.UserId == s.UserId),
EvaluatedSamples = myList.Count(c => c.UserId == s.UserId && c.Status == Status.OK)
};
result.PercentageRealized = (result.TotalSamples / result.EvaluatedSamples) * 100;
return result;
});
发布于 2018-12-13 05:12:10
如果您使用匿名类型,这将更加复杂,但是因为DtoTest
是一个类,所以您可以始终将您的数学运算转移到该属性中。
public class DtoTest
{
public float PercentageRealized
{
get { return (TotalSamples / EvaluatedSamples) * 100; }
}
}
https://stackoverflow.com/questions/53751316
复制相似问题