我们有以下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
});
有没有一种方法可以分配属性值“ PercentageRealized”而不使用以前在“ TotalSamples”和“ EvaluatedSamples”中使用的相同功能?
类似的东西:
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!
});
还有其他提示吗?
答案 0 :(得分:3)
更改函数委托以使用已经计算的值
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;
});
答案 1 :(得分:3)
如果您使用的是匿名类型,这会更加复杂,但是由于DtoTest
是一个类,因此您始终可以将数学运算移到该属性中。
public class DtoTest
{
public float PercentageRealized
{
get { return (TotalSamples / EvaluatedSamples) * 100; }
}
}
答案 2 :(得分:2)
如果PercentageRealized
就是这么简单的计算,为什么不在类的属性中进行计算,就像在DTOTest类中这样:
public float PercentageRealized => (TotalSamples / EvaluatedSamples) * 100;
答案 3 :(得分:1)
首先投影到元组,然后投影到您的自定义对象:
myList.Select(s => (tSample: myList.Count(c=> c.UserId == s.UserId),
eSample : myList.Count(c=> c.UserId == s.UserId && c.Status == Status.OK)))
.Select(x => new DtoTest
{
TotalSamples = x.tSample,
EvaluatedSamples = x.eSample,
PercentageRealized = (x.tSample / x.eSample) * 100
});
或使用匿名类型:
myList.Select(s => new
{
tSample = myList.Count(c=> c.UserId == s.UserId),
eSample = myList.Count(c=> c.UserId == s.UserId && c.Status == Status.OK)
})
.Select(x => new DtoTest
{
TotalSamples = x.tSample,
EvaluatedSamples = x.eSample,
PercentageRealized = (x.tSample / x.eSample) * 100
});
答案 4 :(得分:1)
您正在做的事情对我来说极度可疑-您正在遍历源数据以一次又一次地(每次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]);