使用Iterator Blocks减少嵌套for循环和if语句?

时间:2013-03-24 09:43:52

标签: c#

是否可以减少这个长嵌套for循环以及条件以增加其可读性并优化它以供将来参考。

在为我的调度应用程序编写代码时,我最终得到了如下所示的方法。真的,我有一个像this这样的数据结构。在这里,我检查 - 是否有任何阶段(内部LCycle)同时使用相同的工具,如果找到它,则调用另一个方法LCycleTimeShift进行重新排列。

但是我想检查新的安排是否具有适应性,并且for循环计数器被重置,以便它将再次检查新的安排。我认为这不是编写代码以获得更好的可读性的更好方法。对该主题的一点研究发现,调查员可以帮助我。但我不知道如何使用以下代码完成此操作。

public List<LCycle> ToolArrangment(List<LCycle> TimeLineInit)
{
    for (int i = 0; i < TimeLineInit.Count; i++)//Each LIfeCycles In TimeLine
    {
        for (int j = 0; j < TimeLineInit[i].Stage.Count; j++)//Each Stages inTimeLine
        {
            for (int k = 0; k < i; k++)//Each L esvd =ifeCycles Upto Current LifeCycle
            {
                for (int l = 0; l < TimeLineInit[k].Stage.Count; l++)//Each Stages of (LifeCycle upto current LifeCycle) 
                {
                    for (int m = 0; m < TimeLineInit[i].Stage[j].ToolList.Count; m++)//each tools in stage of timelkine
                    {
                        for (int n = 0; n < TimeLineInit[k].Stage[l].ToolList.Count;n++ )// Each tools In that stage (for loop outer of outer)
                        {
                            if (TimeLineInit[i].Stage[j].ToolList[m].ToolName == TimeLineInit[k].Stage[l].ToolList[n].ToolName)//If both tools are same (satidfying above for loop conditions)
                            {
                                if (IsTimeOverLaps(TimeLineInit[i].Stage[j].StageSpan, TimeLineInit[k].Stage[l].StageSpan))
                                {//tool using at same time.
                                    Stage ReplaceStage = TimeLineInit[i].Stage[j].DeepCopy();//Taking Copy of stage Span to make time shift
                                    Double TimeDifference=(ReplaceStage.StageSpan.ToTime-ReplaceStage.StageSpan.FromTime).TotalMinutes;//Calculating required time shift
                                    ReplaceStage.StageSpan.FromTime=TimeLineInit[k].Stage[l].StageSpan.ToTime;//FromTime changed accordingly
                                    ReplaceStage.StageSpan.ToTime=ReplaceStage.StageSpan.ToTime.AddMinutes(TimeDifference);//To Time Changed accordingly
                                    LCycleTimeShift(TimeLineInit[i], ReplaceStage);//passing refernce
                                    j = 0; k = 0; l = 0; m = 0; n = 0;//Counter Reset to validate the new arrangment
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    return TimeLineInit;
}

3 个答案:

答案 0 :(得分:2)

尝试使用LINQ,尤其是SelectMany和Join方法

var t = TimeLineInit
          .SelectMany(t=>t.Stage)
          .SelectMany(s=>s.ToolList);

... 

t
 .Join(t, [your conditions 1])
 .Join(t, [your conditions 2])

答案 1 :(得分:1)

唯一合理的选择是将迭代内容作为方法放在模型中互相调用,这样它就会更易读,也更容易理解。

答案 2 :(得分:1)

在开始沿着这条路前行之前的一些事情。代码现在有效吗?你有单元测试吗?我只是问,因为在开始任何重构之前,如果你有测试用例就很棒。

关于枚举器的主题,一行代码对我很突出:

LCycleTimeShift(TimeLineInit[i], ReplaceStage);//passing refernce
j = 0; k = 0; l = 0; m = 0; n = 0;//Counter Reset to validate the new arrangment

你不允许在枚举操作中修改一个集合,所以你可能会发现你在该函数中所做的任何魔法都适用于(...),它可能不再适用于foreach (...)或LINQ枚举。仅当它正在删除时,才会将其添加到集合中,而这似乎正在执行。我不得不在下面进行一些更改,因为我假设每次传递后枚举都会改变,这意味着我每次都会重新评估重复项。

正如你所说,似乎你想要找到包含同时使用的同一工具的任何两个阶段(不属于同一个LCycle)。然后,您对该阶段的时间进行一些更改,然后修改父级。我感觉合理。这就是我想出的。我没有任何测试用例,但它可能会让你朝着正确的方向前进。

var toolsInUse = TimeLineInit
                    .SelectMany(cycle => cycle.Stage
                    .SelectMany(stage => stage.ToolList.Select(tool => new
{
    Cycle = cycle,
    Stage = stage,
    Tool = tool.ToolName
})));

var duplicateUse = toolsInUse.Join(toolsInUse, 
                                    x => x.Tool, 
                                    x => x.Tool, 
                                    (a, b) => new { Use = a, Duplicate = b })
                                .Where(x => x.Use.Cycle != x.Duplicate.Cycle &&
                                            IsTimeOverLaps(x.Use.Stage.StageSpan, x.Duplicate.Stage.StageSpan));

while (duplicateUse.Count() > 0)
{
    var item = duplicateUse.First();

    Stage ReplaceStage = item.Use.Stage.DeepCopy();//Taking Copy of stage Span to make time shift
    Double TimeDifference = (ReplaceStage.StageSpan.ToTime - ReplaceStage.StageSpan.FromTime).TotalMinutes;//Calculating required time shift
    ReplaceStage.StageSpan.FromTime = item.Duplicate.Stage.StageSpan.ToTime;//FromTime changed accordingly
    ReplaceStage.StageSpan.ToTime = ReplaceStage.StageSpan.ToTime.AddMinutes(TimeDifference);//To Time Changed accordingly
    LCycleTimeShift(item.Use.Cycle, ReplaceStage);//passing refernce
}

我对性能,准确性没有任何要求。这只是为了指出你的方向。我希望它有所帮助。