使用LINQ在c#中将列表数据转换为具有所需格式的另一种列表数据的最佳方法

时间:2017-07-05 14:43:36

标签: c# list linq

我需要如何在我的项目中插入chart,并使用C3库来执行此操作,这需要特定格式才能生效。

我从我的database检索我的数据,然后我将其转换为此格式

{"TotalbeAbsencesDepartmentByReason":[
[   {"Label":"DQUA","Reason":"AUT","AbsNumber":1,"AbsenceHours":3.75},
    {"Label":"DQUA","Reason":"NOAUT","AbsNumber":1,"AbsenceHours":3.75},
    {"Label":"DQUA","Reason":"CM","AbsNumber":4,"AbsenceHours":32}
],
[{"Label":"DPRO","Reason":"AUT","AbsNumber":10,"AbsenceHours":43.9},{"Label":"DPRO","Reason":"CM","AbsNumber":18,"AbsenceHours":144}],
[{"Label":"DMAI","Reason":"AUT","AbsNumber":2,"AbsenceHours":1.6999999999999993}],
[{"Label":"DENG","Reason":"CM","AbsNumber":2,"AbsenceHours":16}]
]}

我想要处理的格式是:

"TotaleAbsDepartementByReason":
[
    {"Label":"DQUA","Aut":3.75,"NoAut":3.75,"CM":32},
    {"Label":"DPRO","Aut":43.9,"NoAut":0,"CM":144},
    {"Label":"DMAI","Aut":1.6999999999999993,"NoAut":0,"CM":0},
    {"Label":"DENG","Aut":0,"NoAut":0,"CM":16}
]

这是我的解决方案,它完美运行,但我认为还有另一种方法可以提高性能:

var DeptNames = TotalbeAbsencesDepartmentByReason.Select(b => b.Label).Distinct();
var TotaleAbsDepartementByReason = new List<AbsByReason>();
foreach (var name in DeptNames)
{
    var auth = TotalbeAbsencesDepartmentByReason.Where(a => a.Label == name && a.Reason == "AUT").FirstOrDefault();
    var noauth = TotalbeAbsencesDepartmentByReason.Where(a => a.Label == name && a.Reason == "NOAUT").FirstOrDefault();
    var cm = TotalbeAbsencesDepartmentByReason.Where(a => a.Label == name && a.Reason == "CM").FirstOrDefault();
    TotaleAbsDepartementByReason.Add(new AbsByReason
    {
        Aut = auth != null ? auth.AbsenceHours.Value : 0 ,
        CM = cm != null ? cm.AbsenceHours.Value : 0,
        NoAut = noauth != null ? noauth.AbsenceHours.Value : 0,
        Label = name
    });
}

2 个答案:

答案 0 :(得分:2)

您可以稍微更好地组织代码,至少从可维护性的角度来看,删除一些冗余应该可以提高性能。以下是重构代码

public class RowData {
    public string Label { get; set; }
    public string Reason { get; set; }
    public int AbsNumber { get; set; }
    public decimal? AbsenceHours { get; set; }
}

public class AbsByReason {
    public decimal Aut { get; set; }
    public decimal CM { get; set; }
    public string Label { get; set; }
    public object NoAut { get; set; }
}

public static IEnumerable<AbsByReason> TransformData(List<RowData> totalbeAbsencesDepartmentByReason) {
    return totalbeAbsencesDepartmentByReason
                .GroupBy(row => row.Label)
                .Select(XFormLabelGroupToAbsByReason);
}

private static AbsByReason XFormLabelGroupToAbsByReason(IEnumerable<RowData> labelGroup) {
    var reason = new AbsByReason();
    foreach (var rowData in labelGroup) {
        if (rowData.Reason == "AUT")
            reason.Aut = rowData.AbsenceHours ?? 0;
        else if (rowData.Reason == "NOAUT")
            reason.NoAut = rowData.AbsenceHours ?? 0;
        else if (rowData.Reason == "CM")
            reason.CM = rowData.AbsenceHours ?? 0;
    }
    return reason;
}

让我解释一下我做了什么。在这种情况下,使用分组数据时,GroupBy非常有用。对数据进行分组后,只需要转换该组(而不是列表中的所有数据)。您可以使用LINQ,但我宁愿使用简单的for循环和if-else-if组合。我发现在单通道中比在多通道LINQ方式中做事更好,即使你在谈论列表中不超过3个项目。

答案 1 :(得分:0)

我看到的一个问题是您使用不同的过滤谓词遍历原始列表三次。这是一种如何通过一次列表遍历获得相同结果的方法:

        var Depts = new Dictionary<string, AbsByReason>();
        foreach (var entry in TotalbeAbsencesDepartmentByReason)
        {
            AbsByReason abs;
            if (!Depts.TryGetValue(entry.Label, out abs))
                Depts[entry.Label] = abs = new AbsByReason() { Label = entry.Label };
            switch (entry.Reason)
            {
                case "AUT":
                    abs.Aut = entry.AbsenceHours.Value;
                    break;
                case "NOAUT":
                    abs.NoAut = entry.AbsenceHours.Value;
                    break;
                case "CM":
                    abs.CM = entry.AbsenceHours.Value;
                    break;
            }
        }
        var TotaleAbsDepartementByReason = Depts.Select(kvp => kvp.Value).ToList();