我正在使用linq来整形从数据库返回的对象,以便更好地转换为JSON数据以与第三方控件(例如highcharts)一起使用。在对数据进行整形时,我需要确保每个数据点都存在值,即使它们为零。
例如,在查询数据库时,我可能会返回以下对象的列表:
public class DatabaseResponse
{
public string TypeOfService {get;set;}
public string FacilityName {get;set;}
public int ServiceCount {get;set;}
}
现在数据库可能会返回任意数量的这些对象,有时它们的不同TypeOfService
字符串匹配。其他时候他们没有。当我对数据进行整形时,我需要返回几个不同的数据。即,各个ServiceCount
的类别(FacilityNames数组)及其TypeOfService
。
最初我做了类似以下的事情来获取类别:
var result = GetTypeOfServiceCountsByFacility(startDate, endDate, companyDivisionIds, facilityIds, catcCompanyId);
我正在做这样的事情以获得服务计数:
var data = result.OrderBy(n => n.FacilityName).GroupBy(n => n.TypeOfService).Select(n => new {
name = n.Key,
data = n.Select(x => x.ServiceCount).ToArray()
});
如果每个Facility都有匹配的服务,则上述工作非常有效,但如果它们关闭,则阵列关闭。是否有一种简单的方法来填充数据以确保所有内容都被填充(即使它只是零)?
修改
示例输入:
var result = new List<ServiceTypeFacilityCounts>
{
{ new ServiceTypeFacilityCounts {FacilityName = "Facility 2", TypeOfService="Phone", ServiceCount=50 } },
{ new ServiceTypeFacilityCounts {FacilityName = "Facility 2", TypeOfService="Visit", ServiceCount=10 } },
{ new ServiceTypeFacilityCounts {FacilityName = "Facility 2", TypeOfService="Call-In", ServiceCount=3 } },
{ new ServiceTypeFacilityCounts {FacilityName = "Facility 1", TypeOfService="Phone", ServiceCount=5 } }
};
使用上面的代码我的输出将是:
categories = ["Facility 1", Facility 2"]
data = {
[{name: "Phone", data: [5,50]}],
[{name: "Visit", data: [10]}],
[{name: "Call-In", data: [3]}]
}
但实际上它应该是:
categories = ["Facility 1", Facility 2"]
data = {
[{name: "Phone", data: [5,50]}],
[{name: "Visit", data: [0,10]}],
[{name: "Call-In", data: [0,3]}]
}
答案 0 :(得分:1)
您基本上对内部数据项执行左连接。把它写成:
var facilities = results.Select(x => x.FacilityName).Distinct().OrderBy(x => x).ToList();
var query =
from x in results
group x by x.TypeOfService into g
select new
{
Name = g.Key,
Data =
(from c in facilities
join x in g on c equals x.FacilityName into xs
from x in xs.DefaultIfEmpty()
select x?.ServiceCount ?? 0).ToArray()
};
以下是使用方法语法的上述查询的等效版本。
var facilities = results.Select(x => x.FacilityName).Distinct().OrderBy(x => x).ToList();
var query = results.GroupBy(x => x.TypeOfService)
.Select(g => new
{
Name = g.Key,
Data = facilities.GroupJoin(g, c => c, x => x.FacilityName, (c, xs) => xs)
.SelectMany(xs =>
xs.DefaultIfEmpty().Select(x => x?.ServiceCount ?? 0)
).ToArray(),
});
答案 1 :(得分:0)
我提出的一个可能的解决方案是构建一个临时列表,强制迭代类别列表和分组服务类型。然后我尝试从主结果集中选择以查看是否存在值。如果有,我将其添加到新列表中。如果它没有给新列表添加零。那个版本看起来像:
var categories = result.OrderBy(n => n.FacilityName).Select(n => n.FacilityName).Distinct().ToArray();
var paddedData = new List<Tuple<string, int>>();
result.OrderBy(n => n.FacilityName).GroupBy(n => n.TypeOfService).ToList().ForEach(n =>
{
foreach (var category in categories)
{
var newItem = new Tuple<string,int>
(
n.Key,
result.FirstOrDefault(item => item.FacilityName == category && item.TypeOfService == n.Key)?.ServiceCount ?? 0
);
paddedData.Add(newItem);
}
});
var data = paddedData.GroupBy(n => n.Item1).Select(n => new
{
name = n.Key,
data = n.Select(x => x.Item2).ToArray()
});
var shapedData = new
{
series = data,
categories
};