你好伙伴我一直在尝试构建一个Linq查询,它在记录中找到重叠的范围,并构造一个新的单一范围,它将连接两个范围。
public class students
{
public string course { get; set; }
public int idStart { get; set;}
public int idEnd { get; set;}
}
var c1 = new students(){course = "c#", idStart = 1, idEnd = 25};
var j1 = new students(){course = "java",idStart = 50, idEnd = 60};
var c2 = new students(){"c#", 20, 36};
var j2 = new students(){"java", 40, 55};
var c3 = new students(){"c#", 70, 80};
var studentranges = new list<students>;
studentranges.Add(c1);
studentranges.Add(j1);
studentranges.Add(c2);
studentranges.Add(j2);
studentranges.Add(c3);
现在我需要重新格式化List studentranges
,以便产生的结果是
studentranges = list<"c#", 1, 36; "Java", 40, 60; "c#", 70, 80>
虽然在这个例子中我只使用了2个范围的C#&amp; Java的。查询需要对N number of Courses and N number of Ranges
我的代码实现此目的:
var c_range = studentranges.Where(u => u.course == "c#")
.OrderBy(u => u.idStart)
.ToList();
//assuming c_least is bound to exist for simplicity
var c_least = c_range.first();
var c_next = c_range.Where( u=> u.idStart > c_least.idStart && u.idEnd >= c_least.idEnd)
.First();
//assuming c_next is not null
c_least.idEnd = c_next.idEnd;
如何进一步复发?
答案 0 :(得分:1)
这似乎适用于您的输入,请检查它是否适用于更多类型和输入。
public class Students
{
public Students(Course c, int start, int end)
{
MyCourse = c;
idStart = start;
idEnd = end;
}
// public string course { get; set; }
public int idStart { get; set; }
public int idEnd { get; set; }
public Course MyCourse { get; set; }
}
public enum Course { CSharp, Java }
public class MiscTests
{
private List<Students> students;
private List<Students> result;
public MiscTests()
{
students = new List<Students>
{
new Students(Course.CSharp, 1, 25),
new Students(Course.Java, 50, 60),
new Students(Course.CSharp, 20, 36),
new Students(Course.Java, 40, 55),
new Students(Course.CSharp, 70, 80),
};
result = new List<Students>();
}
public void Run()
{
students = students.OrderBy(s => s.idEnd).ThenBy(s=>s.MyCourse).ToList();
foreach (var s in students)
{
var lastOne = result.LastOrDefault(r=>r.MyCourse == s.MyCourse);
if (lastOne == null)
{
result.Add(s);
}
else
{
var last = result.Last();
if (lastOne.MyCourse == last.MyCourse)
{
lastOne.idEnd = Math.Max(s.idEnd, lastOne.idEnd);
lastOne.idStart = Math.Min(s.idStart, lastOne.idStart);
}
else
{
result.Add(s);
}
}
}
}
}
答案 1 :(得分:1)
我做了类似日期的事情并确保它们没有重叠。我使用了矩形和Intersect method来确定日期是否重叠。我想你可以做类似的事情来获取你的清单。对于那些与你相交的人,你可以把它们结合在一起。
答案 2 :(得分:1)
使用GroupBy按顺序对记录进行分组,为每个组构建重叠记录,并将所有新记录合并到一个包含SelectMany的列表中:
var result =
studentranges.GroupBy(s => s.course)
.SelectMany(GetRangesForGroup)
.ToList();
GetRangesForGroup
使用您尝试的相同基本方法:按idStart
排序并找到下一个idEnd
。完整代码:
private static IEnumerable<Student> GetRangesForGroup(IGrouping<string, Student> group) {
var studentEnumerator = group.OrderBy(s => s.idStart).GetEnumerator();
// move to first record and initialize range variables
studentEnumerator.MoveNext();
var idStart = studentEnumerator.Current.idStart;
var idEnd = studentEnumerator.Current.idEnd;
// iterate remaining records
while (studentEnumerator.MoveNext()) {
if (studentEnumerator.Current.idStart <= idEnd) {
// current range starts before previous end point -- it overlaps
// use the farthest end point
if (studentEnumerator.Current.idEnd > idEnd) {
idEnd = studentEnumerator.Current.idEnd;
}
} else {
// the current range is non-overlapping
// output previous range
yield return new Student() { course = group.Key, idStart = idStart, idEnd = idEnd };
// reinitialize variables for next range
idStart = studentEnumerator.Current.idStart;
idEnd = studentEnumerator.Current.idEnd;
}
}
// output final range
yield return new Student() { course = group.Key, idStart = idStart, idEnd = idEnd };
}