[英]How do I create a list object that contains a list of another object type using from within a query using linq and c#
[英]how do i pivot list of object and create new list in linq c#?
我有一份员工每天工作时间数据的列表。 我想透视日期和小时数据,并创建一个新的对象列表,其中包含员工姓名,以及以相应小时数为值的一系列天数。
我的清单看起来像
List<EmployeeHour> employeeHours = new List<EmployeeHour>
{
new EmployeeHour{Id = 1, EmployeeName = "Emp1", Day = 1, Hours = 6},
new EmployeeHour{Id = 1, EmployeeName = "Emp1", Day = 2, Hours = 8},
new EmployeeHour{Id = 2, EmployeeName = "Emp2", Day = 1, Hours = 6},
new EmployeeHour{Id = 2, EmployeeName = "Emp2", Day = 2, Hours = 8}
};
我想创建新的对象列表,其中的时间类似于
new {
Id = 1,
EmplyeeName = Emp1,
Day1 = 6,
Day2 = 8
},
new {
Id = 2,
EmplyeeName = Emp2,
Day1 = 6,
Day2 = 8
}
我就是这样做的。 有更好的解决方案吗?
dynamic d = new
{
Employee = group.FirstOrDefault().EmployeeName,
Day1 = group.FirstOrDefault(g => g.DayNumber == 1)?.HoursPerDay,
Day2 = group.FirstOrDefault(g => g.DayNumber == 2)?.HoursPerDay,
Day3 = group.FirstOrDefault(g => g.DayNumber == 3)?.HoursPerDay,
Day4 = group.FirstOrDefault(g => g.DayNumber == 4)?.HoursPerDay,
Day5 = group.FirstOrDefault(g => g.DayNumber == 5)?.HoursPerDay,
Day6 = group.FirstOrDefault(g => g.DayNumber == 6)?.HoursPerDay,
Day7 = group.FirstOrDefault(g => g.DayNumber == 7)?.HoursPerDay
};
list.Add(d);
C# 是一种强类型语言,因此类属性的可变性是有限的。 似乎更适合您的是Dictionary<string, object>
:
var dictionaries = employeeHours.Select(x => new {x.Id, x.EmployeeName})
.Distinct()
.Select(x => new Dictionary<string, object>()
{
{"Id", x.Id},
{"EmployeeName", x.EmployeeName}
})
.ToList();
foreach (var dict in dictionaries)
{
var id = (int)dict["Id"];
foreach (var dh in employeeHours.Where(x => x.Id == id))
{
if (!dict.ContainsKey("Day" + dh.Day))
{
dict["Day" + dh.Day] = dh.Hours;
}
}
}
这段代码会给你一个可变长度的字典,当它使用 JSON 转换时,它应该为你提供数据表中所需的数据结构。
如果您希望结果是静态类型的匿名(或定义的类)对象,则需要执行类似于您正在执行的操作。
我将使用从每个组转换而来的增强型字典类型,以便更轻松地提取值:
//***
// Enhanced Dictionary that returns default(TValue) for missing values
//***
public class NullDictionary<TKey, TValue> : Dictionary<TKey, TValue> {
public NullDictionary(IDictionary<TKey, TValue> d) : base() {
foreach (var kvp in d)
Add(kvp.Key, kvp.Value);
}
public NullDictionary() : base() { }
public new TValue this[TKey key]
{
get
{
TryGetValue(key, out var val);
return val;
}
set
{
base[key] = value;
}
}
}
使用扩展方法使创建变得容易:
public static class DictExt {
public static NullDictionary<TKey, TValue> ToNullDictionary<T, TKey, TValue>(this IEnumerable<T> src, Func<T, TKey> keyFn, Func<T, TValue> valFn) {
var nd = new NullDictionary<TKey, TValue>();
foreach (var s in src)
nd.Add(keyFn(s), valFn(s));
return nd;
}
}
现在您可以使用GroupBy
透视数据并提取匿名对象:
var ans = employeeHours.GroupBy(eh => new { eh.Id, eh.EmployeeName }, eh => new { Day = $"Day{eh.Day}", eh.Hours })
.Select(pg => {
var pd = pg.ToNullDictionary(p => p.Day, p => (int?)p.Hours);
return new {
pg.Key.Id,
pg.Key.EmployeeName,
Day1 = pd["Day1"],
Day2 = pd["Day2"],
Day3 = pd["Day3"],
Day4 = pd["Day4"],
Day5 = pd["Day5"],
Day6 = pd["Day6"],
Day7 = pd["Day7"],
};
})
.ToList();
还可以为每个列表成员使用更动态的对象,例如DataTable
或Dictionary
或ExpandoObject
,甚至可以在运行时创建匿名对象,尽管在大多数情况下这是有问题的价值,因为您可以' t 轻松访问其字段。 但是,如果您不知道Day
值是如何可能的,并且想要处理不同的数字,则必须使用这些值之一或用某种类型的集合代替 day 字段(例如数组、列表或字典) )。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.