2016-07-22 99 views
1

我有一个对象集合,我需要迭代并执行某些操作。目前看来很简单。但是,我有一些使它相当复杂的条件。具有多个逻辑条件的foreach循环

下面是一些信息:

的集合,包含了一些具有行星相位次“行星”对象的。

如果两个阶段之间的时间间隔小于或等于30分钟,则行星观看时间将组合为块。

例如,这里是6周阶段时间:

  • 阶段1:上午8:00 - 上午9:30
  • 阶段2:上午10点 - 上午11点
  • 阶段3: 11:20 AM - 12:30 PM
  • 阶段4:下午2:00 - 下午4:00
  • 阶段5:下午6:30 - 下午7:30
  • 阶段6:下午7:45 - 下午9:00

利用上述数据,我们有以下的块:通过3阶段1

  • 相:一个连续观看块
  • 阶段4:单独观察块
  • 阶段5和第6阶段:一个continuuous观看块

数学:

  • (阶段2开始时间) - (第1阶段结束时间)=30分钟
  • (第3阶段开始时间) - (第2阶段结束时刻)=20分钟
  • (第4阶段开始时间) - (第3阶段结束的时间)=90分钟
  • (第5阶段开始时间) - (第4阶段结束时刻)=150分钟
  • (相位6开始时间) - (结束时间相5)=15分钟

到目前为止我的失败尝试:

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

执行阶段圈午夜后回来?换句话说,'早上12:15 - 凌晨2:30'和晚上10点 - 晚上11:50是否构成一次观看? – dasblinkenlight

+0

If continueBlocking do X,else do X. X = X.那么为什么你使用continueBlocking? – Berkay

+0

你是否研究过使用case语句而不是多个if语句? – tCoe

回答

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 
+0

我接受了你的答案,但使用上面的代码,它不能解决'开始'或'结束'符号。 – SkyeBoniwell

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 AM - 2016/7/22 12:30:00 PM

2016/7/22 2:00:00 - 7/22/2016 4:00:00 PM

2016年7月22日下午六时30分00秒 - 2016年7月22日下午九时00分零零秒