Linq Flatten List of List



使用Linq用这两个对象创建扁平列表的最佳方法是什么

public class DataDto
{
public string StudentID { get; set; }
public List<ScoreDto> Scores { get; set; }
}
public class ScoreDto
{
public string ExamID { get; set; }
public double Mark { get; set; }
}

将放入列表中,该列表将显示为

public class FinalDto
{
public string StudentID { get; set; }
public string ExamID { get; set; }
public double Mark { get; set; }
}

StudentID的重复次数表示某一特定学生ScoreDtos的出现次数。

示例数据-

var data = new List<DataDto>()
{
new DataDto
{ 
StudentID = "S1", 
Scores = new List<ScoreDto>()
{ 
new ScoreDto { ExamID = "01", Mark = 5},
new ScoreDto { ExamID = "02", Mark = 15},
new ScoreDto { ExamID = "03", Mark = 25}
}
},
new DataDto
{
StudentID = "S2",
Scores = new List<ScoreDto>()
{
new ScoreDto { ExamID = "01", Mark = 1},
new ScoreDto { ExamID = "02", Mark = 5},
new ScoreDto { ExamID = "03", Mark = 20}
}
}
};

生成-

StudentID, ExamID, Mark
S1, 01, 5
S1, 02, 15
S1, 03, 25
S2, 01, 1
S2, 02, 5
S2, 03, 20

您使用SelectMany来平化列表的列表:

var final = data.SelectMany(
student => student.Scores, 
(student, score) => new FinalDto { 
StudentID = student.StudentID, 
ExamID = score.ExamID, 
Mark = score.Mark 
}
);
Console.WriteLine("StudentID, ExamID, Mark");
foreach (var result in final)
{
Console.WriteLine("{0}, {1}, {2}", result.StudentID, result.ExamID, result.Mark);
}

或者,您可以使用SelectMany的不同重载以及嵌套的Select投影:

var final = data.SelectMany(
student => student.Scores.Select(
score => new FinalDto { 
StudentID = student.StudentID, 
ExamID = score.ExamID, 
Mark = score.Mark 
}
)
);

您也可以使用查询语法:

var final = (
from student in data
from score in student.Scores
select new FinalDto { 
StudentID = student.StudentID,
ExamID = score.ExamID, 
Mark = score.Mark 
}
);

注意,这只是转换成上面所示的第二种形式。

没有"最佳"在这里。表单2和表单3可以编译成完全相同的代码。形式一只是一个小小的变化。选择一个而不是另一个没有影响(速度、内存)。选择一个视觉上吸引你的。就我个人而言,我不写查询语法(最后一种形式),我总是忘记第一个重载存在,所以我最终使用第二个。

var result = (
from item in data
from score in item.Scores
select new FinalDto {
StudentID = item.StudentID, 
ExamID = score.ExamID,
Mark = score.Mark
}).ToList();

有两个一对多关系的表:表a的每一项都有0个或多个来自表B的项,并且表B的每一项都只属于表a的一个项,即外键所指向的一个项。

当你有了这个,并且你想要"项及其子项",比如学校及其学生,客户及其订单,作者及其图书,考虑使用Queryable重载之一。GroupJoin

如果您不想要包含子项的项,而是一个平面表,请考虑使用Queryable。加入

显然,您已经获取了"分数为零或更高的学生",并且您想要一个平坦的结果。在这种情况下,使用SelectMany

IEnumerable<DataDto> studentsWithTheirScores = ...
var result = studentsWithTheirScores.SelectMany(
// parameter collectionSelector: where are the sub-items stored?
student => student.Scores,
// parameter resultSelector: take each student, and each one of his Scores
// to make one new
(student, score) => new FinalDto
{
StudentId = student.StudentId,
ExamId = score.ExamId,
Mark = score.Mark,
});

最新更新