更新我还需要保留List<T>
中来自List<U>
的员工的第一个条目的索引以供日后使用。目前我正在使用从Nicolas's answer下面修改的代码
List<EmployeeRollup> summary =
details
.GroupBy( e => e.EmployeeId , StringComparer.OrdinalIgnoreCase )
.Select( g => new EmployeeRollup {
EmployeeId = g.Key ,
ProjectDateFrom = g.Min( e => e.ProjectDate ) ,
ProjectDateThru = g.Max( e => e.ProjectDate ) ,
FullRecordsRef = employee
.FindIndex(f => f.employeeId == g.Key),
ProjectCodes = g.Select( e => e.ProjectCode )
.Distinct( StringComparer
.OrdinalIgnoreCase )
.ToArray() ,
}).ToList();
这种做法是否正确?有没有更有效的方法呢?
<- End Update ->
我有一个应用程序,我想将对象列表List<T>
转换为另一个对象列表List<U>
原始列表(List<T>
)为List<Employee>
,其中Employee
定义为
class Employee{
public string empid;
public Date proj_date;
public string proj_code;
// other fields and methods
}
,列表中的数据看起来像
empid proj_date proj_code
01 21/Nov/2014 02
01 21/Nov/2014 03
02 21/Nov/2014 09
02 22/Nov/2014 99
02 23/Nov/2014 09
03 21/Nov/2014 15
03 01/Dec/2014 16
我想将此List<Employee>
转换为另一个列表,List<Emp2>
其中Emp2
定义为
class Emp2{
public string empid;
public Date min_proj_date;
public Date max_proj_date;
public string [] proj_code;
// other fields and methods
}
从List<Employee>
转换后,List<Emp2>
中的数据应如下所示
empid min_proj_date max_proj_date proj_code[]
01 21/Nov/2014 21/Nov/2014 [02, 03]
02 21/Nov/2014 23/Nov/2014 [09,99]
03 21/Nov/2014 01/Dec/2014 [15,16]
所以我正在做的是
我尝试使用MoreLINQ库中的DistinctBy
函数,但无法解决问题。
答案 0 :(得分:2)
您可以使用GroupBy
和Select
从一个转换为另一个,如下所示:
var myEmps = new List<Employee> { /* data here */ };
var myEmp2s = myEmps
.GroupBy(x => x.empid)
.Select(x => new Emp2
{
empid= x.Key,
min_project_date = x.Min(y => y.proj_date),
max_project_date = x.Max(y => y.proj_date),
proj_code = x.Select(y => y.proj_code).ToArray()
// Other fields are rolled up in a similar fashion as needed
});
答案 1 :(得分:2)
主要有两种方法。第一个是继续使用list.Select(emp => new { foo = emp.Where(e => e.empid == emp.empid) })
来选择初始列表...但这在计算上很糟糕,并且不如... GroupBy
惯用。
您似乎还想要一些OrderBy
和Distinct
条款,而Date
可能意味着DateTime
?否则,根据需要进行调整。
var empGroups = emp.GroupBy(e => e.empid);
empGroups.Select(g => new {
empid = g.Key,
min_proj_date = g.Min(e => e.proj_date.Date),
max_proj_date = g.Min(e => e.proj_date.Date),
proj_code = g.Select(e => e.proj_code).OrderBy(pc => pc).Distinct().ToArray()
})
通过首次分组,您可以对该组的Key
进行操作以供将来汇总和选择。然后,为输出选择一种新类型,并在属性本身上进行第二次内部选择。
请注意GroupBy
结果的枚举类型为IGrouping<(string) TKey, (Employee) TElement>
inherits from IEnumerable<TElement>
。抓取g
后,其类型现为IEnumerable<Employee>
,并且可以访问g.Key
。从那时起,像对待任何其他IEnumerable
那样对待它,并使用熟悉的LINQ。这基本上是实例化变量,循环和添加到列表的替代方法;变量在lambda中定义并提升到你的lambda中。
答案 2 :(得分:1)
没有比
复杂得多public class Employee
{
public string EmployeeId ;
public DateTime ProjectDate ;
public string ProjectCode ;
}
public class EmployeeRollup
{
public string EmployeeId ;
public DateTime ProjectDateFrom ;
public DateTime ProjectDateThru ;
public string[] ProjectCodes ;
}
class Program
{
static void Main(string[] args)
{
List<Employee> details = new List<Employee>() ;
List<EmployeeRollup> summary =
details
.GroupBy( e => e.EmployeeId , StringComparer.OrdinalIgnoreCase )
.Select( g => new EmployeeRollup {
EmployeeId = g.Key ,
ProjectDateFrom = g.Min( e => e.ProjectDate ) ,
ProjectDateThru = g.Max( e => e.ProjectDate ) ,
ProjectCodes = g.Select( e => e.ProjectCode )
.Distinct( StringComparer
.OrdinalIgnoreCase )
.ToArray() ,
})
.ToList()
;
}
}
如果您想跟踪原始列表中每个Employee
实例的偏移量(位置),您可以执行以下操作:
List<Employee> details = new List<Employee>() ;
int i = 0 ;
List<EmployeeRollup> summary =
details
.Select( e => new KeyValuePair<int,Employee>(i,e) )
.GroupBy( kvp => kvp.Value.EmployeeId , StringComparer.OrdinalIgnoreCase )
...
现在您的分组为KeyValuePair<int,Employee>
,其中每个KeyValuePair
Key
属性是原始列表中的整数位置,其Value
属性为原始Employee
实例。
只需进行更改即可。