首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用LINQ从类属性计算百分比的更好方法

使用LINQ从类属性计算百分比的更好方法
EN

Stack Overflow用户
提问于 2018-12-13 05:04:35
回答 5查看 252关注 0票数 1

我们有以下定义LINQ:

代码语言:javascript
运行
复制
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“?

就像这样:

代码语言:javascript
运行
复制
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!
});

还有其他建议吗?

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2018-12-13 05:44:30

对我来说,您所做的似乎非常有问题--您正在对源数据进行多次遍历,以一遍又一遍地重新计算相同的东西(每次出现UserId),而实际上您应该希望的是对每个UserId计算一次,如下所示:

代码语言:javascript
运行
复制
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

如果你真的想要返回多个结果,并且想要高效(因为我喜欢扩展方法),那么创建一个扩展方法来计算一次遍历的链式谓词:

代码语言:javascript
运行
复制
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);
    }
}

现在,您可以在一次遍历中计算子值并计算第三个值:

代码语言:javascript
运行
复制
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的大小,计算每个答案一次,然后重复一次作为最终答案可能会更好:

代码语言:javascript
运行
复制
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]);
票数 1
EN

Stack Overflow用户

发布于 2018-12-13 05:11:26

更改函数委托以使用已计算的值

代码语言:javascript
运行
复制
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;
});
票数 3
EN

Stack Overflow用户

发布于 2018-12-13 05:12:10

如果您使用匿名类型,这将更加复杂,但是因为DtoTest是一个类,所以您可以始终将您的数学运算转移到该属性中。

代码语言:javascript
运行
复制
public class DtoTest
{
    public float PercentageRealized
    {
        get { return (TotalSamples / EvaluatedSamples) * 100; }
    }
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53751316

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档