我有一组对象需要迭代并完成。到目前为止似乎很容易。但是,我有一些条件让它变得相当复杂。
以下是一些信息:
该集合包含一堆具有行星相位时间的“Planet”对象。
如果两个阶段之间的时间跨度小于或等于30分钟,则行星观察时间会合并成块。
例如,这里有6个阶段时间:
根据上述数据,我们有以下几个块:
数学:
到目前为止我的尝试失败了:
int i = 0;
bool continueBlocking = false;
foreach (var p in GalaxySector) //IEnumerable
{
//ensure that dates are not null
if (p.StartDatePhase != null || p.EndDatePhase != null) {
if (continueBlocking) {
string planetName = p.Name;
string planetCatalogId = p.CatalogId;
datetime? StartPhase = p.StartDatePhase.Value;
datetime? EndPhase = p.EndDatePhase.Value;
} else {
string planetName = p.Name;
string planetCatalogId = p.CatalogId;
datetime? StartPhase = p.StartDatePhase.Value;
datetime? EndPhase = p.EndDatePhase.Value;
}
if (i < 2) {
continue;
}
TimeSpan? spanBetweenSections = StartPhase - EndPhase;
if ( spanBetweenSections.Value.TotalMinues <= 30) {
continueBlocking = true;
continue;
} else {
CreateSchedule(planetName, planetCatalogId, StartPhase, EndPhase);
continueBlocking = false;
}
}
i++;
}
我在这个愚蠢的循环上花了好几个小时,我认为另一组眼睛会做得很好。
感觉/看起来太复杂,太老式,太混乱。有没有更好/现代的方式来做这件事?
谢谢!
答案 0 :(得分:1)
假设这些是日期,而不仅仅是一天中的某些时间,您可以执行以下操作
var galaxySector = new List<PlanetPhase>
{
new PlanetPhase
{
Name = "Saturn",
StartDatePhase = new DateTime(2016, 7, 22, 8, 0, 0),
EndDatePhase = new DateTime(2016, 7, 22, 9, 30, 0)
},
new PlanetPhase
{
Name = "Saturn",
StartDatePhase = new DateTime(2016, 7, 22, 10, 0, 0),
EndDatePhase = new DateTime(2016, 7, 22, 11, 0, 0)
},
new PlanetPhase
{
Name = "Saturn",
StartDatePhase = new DateTime(2016, 7, 22, 11, 20, 0),
EndDatePhase = new DateTime(2016, 7, 22, 12, 30, 0)
},
new PlanetPhase
{
Name = "Saturn",
StartDatePhase = new DateTime(2016, 7, 22, 14, 0, 0),
EndDatePhase = new DateTime(2016, 7, 22, 16, 0, 0)
},
new PlanetPhase
{
Name = "Saturn",
StartDatePhase = new DateTime(2016, 7, 22, 18, 30, 0),
EndDatePhase = new DateTime(2016, 7, 22, 19, 30, 0)
},
new PlanetPhase
{
Name = "Saturn",
StartDatePhase = new DateTime(2016, 7, 22, 19, 45, 0),
EndDatePhase = new DateTime(2016, 7, 22, 21, 0, 0)
},
};
PlanetPhase previous = null;
int groupon = 0;
var results = galaxySector.GroupBy(p => p.Name)
.Select(grp => new
{
PlanetName = grp.Key,
Phases = grp.OrderBy(p => p.StartDatePhase)
.Select(p =>
{
if (previous != null
&& p.StartDatePhase - previous.EndDatePhase > TimeSpan.FromMinutes(30))
{
groupon++;
}
previous = p;
return new
{
groupOn = groupon,
p.StartDatePhase,
p.EndDatePhase
};
})
.GroupBy(x => x.groupOn)
.Select(g => new
{
Start = g.Min(x => x.StartDatePhase),
End = g.Max(x => x.EndDatePhase)
})
.ToList()
});
foreach (var r in results)
{
Console.WriteLine(r.PlanetName);
foreach (var p in r.Phases)
Console.WriteLine($"\t{p.Start} - {p.End}");
}
那将输出
土星
2016/7/22 8:00:00 - 7/22/2016 12:30:00 PM
2016/7/22 2:00:00 PM - 7/22/2016 4:00:00 PM
2016/7/22 6:30:00 - 7/22/2016 9:00:00 PM
答案 1 :(得分:1)
如果使用yield return
将多个循环打包到可枚举返回方法中,则可以非常方便地进行分组:
private static readonly TimeSpan HalfHour = TimeSpan.Parse("0:30");
private static IEnumerable<Schedule> Group(IList<GalaxySector> all) {
// Protect from division by zero
if (all.Count == 0) {
yield break;
}
// Find initial location
var pos = 0;
while (pos < all.Count) {
var prior = (pos + all.Count - 1) % all.Count;
if (all[prior].End+HalfHour >= all[pos].Begin) {
pos++;
} else {
break;
}
}
// Protect from wrap-around when all items belong to a single window
pos = pos % all.Count;
// Start grouping items together
var stop = pos;
do {
var start = pos;
var next = (pos+1) % all.Count;
while (next != stop && all[pos].End+HalfHour >= all[next].Begin) {
pos = next;
next = (pos+1) % all.Count;
}
yield return new Schedule {Begin = all[start].Begin, End = all[pos].End};
pos = next;
} while (pos != stop);
}
上面的代码在午夜(demo)执行“环绕”。
方法相对简单:第一个循环通过向后退一步找到开始迭代的位置,以便在循环之后计划是连续的。第二个循环记住起始位置,并一次前进一步,检查窗口是否比半小时分开。一旦找到足够大的中断,或者当我们再次到达起点时,第二个循环就会停止。
如果您不想使用yield return
,可以将项目添加到List<Schedule>
来替换它。
var all = new GalaxySector[] {
new GalaxySector {Begin=TimeSpan.Parse("0:15"), End=TimeSpan.Parse("2:30")}
, new GalaxySector {Begin=TimeSpan.Parse("2:45"), End=TimeSpan.Parse("3:30")}
, new GalaxySector {Begin=TimeSpan.Parse("8:00"), End=TimeSpan.Parse("9:30")}
, new GalaxySector {Begin=TimeSpan.Parse("10:00"), End=TimeSpan.Parse("11:00")}
, new GalaxySector {Begin=TimeSpan.Parse("11:20"), End=TimeSpan.Parse("12:30")}
, new GalaxySector {Begin=TimeSpan.Parse("14:00"), End=TimeSpan.Parse("16:00")}
, new GalaxySector {Begin=TimeSpan.Parse("18:30"), End=TimeSpan.Parse("19:30")}
, new GalaxySector {Begin=TimeSpan.Parse("19:45"), End=TimeSpan.Parse("21:00")}
, new GalaxySector {Begin=TimeSpan.Parse("22:00"), End=TimeSpan.Parse("23:50")}
};
foreach (var sched in Group(all)) {
Console.WriteLine("{0}..{1}", sched.Begin, sched.End);
}
输出:
08:00:00..12:30:00
14:00:00..16:00:00
18:30:00..21:00:00
22:00:00..03:30:00