C# Linq查询连接重叠范围并构造新的连续范围
大家好,我一直在尝试构造一个Linq查询,该查询在记录中查找重叠的范围,并构造一个新的单一范围,该范围将连接两个范围C# Linq查询连接重叠范围并构造新的连续范围,c#,linq,C#,Linq,大家好,我一直在尝试构造一个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, idE
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);
虽然在这个例子中,我只使用了两个C#&Java范围。查询需要灵活处理N个课程数和N个范围数
实现此目的的代码:
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;
如何进一步递归?这似乎适用于您的输入,请检查它是否适用于更多类型和输入
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);
}
}
}
}
}
公共班级学生
{
公立学生(课程c,整数开始,整数结束)
{
MyCourse=c;
idStart=开始;
idEnd=结束;
}
//公共字符串课程{get;set;}
public int idStart{get;set;}
public int idEnd{get;set;}
公共课程MyCourse{get;set;}
}
公共枚举课程{CSharp,Java}
公开课考试
{
私人名单学生;
私有列表结果;
公共测试()
{
学生=新名单
{
新生(Course.CSharp,1,25),
新生(Course.Java,50,60),
新生(Course.CSharp,20,36),
新生(Course.Java,40,55),
新生(Course.CSharp,70,80),
};
结果=新列表();
}
公开募捐
{
students=students.OrderBy(s=>s.idEnd).ThenBy(s=>s.MyCourse.ToList();
foreach(学生中的var s)
{
var lastOne=result.LastOrDefault(r=>r.MyCourse==s.MyCourse);
if(lastOne==null)
{
结果。添加(s);
}
其他的
{
var last=result.last();
如果(lastOne.MyCourse==last.MyCourse)
{
lastOne.idEnd=Math.Max(s.idEnd,lastOne.idEnd);
lastOne.idStart=Math.Min(s.idStart,lastOne.idStart);
}
其他的
{
结果。添加(s);
}
}
}
}
}
我对日期做了类似的处理,确保它们不会重叠。我使用矩形和矩形来确定日期是否重叠。我想你可以做一些类似的事情来得到你的清单。对于相交的记录,您可以将它们合并在一起。按课程将记录分组,为每个组建立重叠记录,并将所有新记录合并到一个列表中,其中包括:
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 };
}
私有静态IEnumerable GetRangesForGroup(iGroup组){
var studentEnumerator=group.OrderBy(s=>s.idStart).GetEnumerator();
//移动到第一个记录并初始化范围变量
studentEnumerator.MoveNext();
var idStart=studentemulator.Current.idStart;
var idEnd=studentemulator.Current.idEnd;
//迭代剩余记录
while(studentEnumerator.MoveNext()){
if(studentEnumerator.Current.idStart-idEnd){
idEnd=studentemulator.Current.idEnd;
}
}否则{
//当前范围不重叠
//输出上一范围
yield return new Student(){course=group.Key,idStart=idStart,idEnd=idEnd};
//为下一个范围重新初始化变量
idStart=studentEnumerator.Current.idStart;
idEnd=studentemulator.Current.idEnd;
}
}
//输出最终范围
yield return new Student(){course=group.Key,idStart=idStart,idEnd=idEnd};
}
您是否简单地尝试合并两个列表?我想让重叠的ID合并为列表中的一个。我想您的答案是list1.Union(list2).Distinct(aCustomComparer).ToList()
查看此处了解更多信息尝试时,您遇到了什么问题?我认为你不应该在林克这样做。Foreach在这类问题上做得更好。你的问题难以理解。您应该将其重新格式化以使其更加清晰。当添加第三个重叠范围{CSharp,20,81}
--将导致单个CSharp范围从1到81时,这似乎不起作用。
var result =
studentranges.GroupBy(s => s.course)
.SelectMany(GetRangesForGroup)
.ToList();
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 };
}