【问题标题】:Need help on refactoring a deeply nested code需要帮助重构深度嵌套的代码
【发布时间】:2011-06-20 08:13:11
【问题描述】:
#include <iostream>
using namespace std;

int main()
{
    int range = 20;
    int totalCombinations = 0;

    for(int i=1; i<=range-2; i++)
    {
        if(range>i)
        {
            for(int j=1; j<=range-1; j++)
                if(j>i)
                {
                    for(int k=1; k<=range-1; k++)
                        if(k>j)
                        {
                            for(int l=1; l<=range-1; l++)
                                if(l>k)
                                {
                                    for(int m=1; m<=range-1; m++)
                                        if(m>l)
                                        {
                                            for(int f=1; f<=range; f++)
                                                if(f>m)
                                                {
                                                    cout << " " <<i<< " " <<j<< " " <<k<< " " <<l<< " " <<m<< " " <<f;
                                                    cin.get(); //pause
                                                    totalCombinations++;
                                                }
                                        }
                                }
                        }
                }
        }
    }
    cout << "TotalCombinations:" << totalCombinations;
}

【问题讨论】:

  • 不小心被标记为 C. 抱歉!

标签: c++ refactoring


【解决方案1】:
if(range>i)

为什么不直接从 range 开始 i 并避免这个问题? 哦,我倒过来了,但重点是——你可以轻松地将它重构为 @ 的一部分987654324@ 条件。不需要额外的条件。

if(j>i)

为什么不直接从j 开始i?

...(重复其他两个循环)

这消除了一半的嵌套。就循环本身而言,我建议对它们使用提取方法。

【讨论】:

    【解决方案2】:

    你可以做的第一件事是using continue:

    for(int i=1; i<=range-2; i++) {
    {
        if(range<=i) {
           continue;
        }
    
        for(int j=1; j<=range-1; j++) {
            if(j<=i) {
               continue;
            }
            //etc for all inner loops
        }
    }
    

    这将大大减少嵌套并提高 IMO 的可读性。

    【讨论】:

    • 你可以这样做。或者您可以消除完全冗余的 IF 测试(正如我所指定的......)。 +1,因为这可以更普遍地解决问题,但我认为对于这种特定情况存在更好的解决方案。
    • 以使代码不可读和不可维护为代价。首先这就是Billy ONeal 所说的:消除不必要的ifs。 (对于它的价值,第一个 if 总是错误的。)
    • @James Kanze:我同意这些检查是不必要的,但我建议的重构可以正式进行,这样会更容易注意到这些检查是不必要的。
    • @sharptooth 什么重构。您提出的建议会使流程复杂化,并使任何关于正在发生的事情的分析变得更加困难。
    • @James Kanze:这是非常主观的。我个人发现带有continue 的代码更容易分析。
    【解决方案3】:

    就像你重构任何东西一样。你首先要弄清楚什么 代码正在做。在这种情况下,许多测试是不相关的,并且 每个循环基本上都做同样的事情。你已经解决了一个非常 一个更普遍的问题的具体案例(非常草率)。锻炼身体 问题的一般算法将导致更清洁,更简单 解决方案,一种更通用的解决方案。像这样的:

    class Combin
    {
        int m;
        int n;
        int total;
        std::vector<int> values;
    
        void calc();
        void dumpVector() const;
    public:
        Combin( int m, int n ) : m(m), n(n), total(0) {}
        int operator()() { total = 0; values.clear(); calc(); return total; }
    };
    
    void 
    Combin::calc()
    {
        if ( values.size() == m ) {
            dumpVector();
            ++ total;
        } else {
            values.push_back( values.empty() ? 0 : values.back() + 1 );
            int limit = n - (m - values.size());
            while ( values.back() < limit ) {
                calc();
                ++ values.back();
            }
            values.pop_back();
        }
    }
    
    void
    Combin::dumpVector() const
    {
        for (std::vector<int>::const_iterator iter = values.begin(); iter != values.end(); ++ iter )
            std::cout << ' ' << *iter + 1;
        std::cout << '\n';
    }
    
    int main()
    {
        Combin c( 6, 20 );
        std::cout << "TotalCombinations:" << c() << std::endl;
        return 0;
    }
    

    上面唯一真正值得评论的是计算 limit 中的 calc,这实际上只是一种优化;你可以 使用n 并获得相同的结果(但你会递归更多一点)。

    您会注意到,在您的原始版本中, 循环或多或少是任意的:系统地使用range 工作,或者你可以计算出我用于limit 的公式( 将导致每个循环的结束条件不同。

    另外,我的代码使用了 C 中普遍存在的半开区间和 C++。我想一旦你习惯了它们,你会发现它们很多 更容易推理。

    【讨论】:

      【解决方案4】:

      我的 C++ 生锈了,所以让我给你一个 C# 的例子。任意数量的嵌套循环都可以只替换为一个,如下所示:

          public void ManyNestedLoopsTest()
          {
              var limits = new[] {2, 3, 4};
              var permutation = new[] {1, 1, 0};
              const int lastDigit = 2;
              var digitToChange = lastDigit;
              while(digitToChange >= 0)
              {
                  if (permutation[digitToChange] < limits[digitToChange])
                  {
                      permutation[digitToChange]++;
                      digitToChange = lastDigit;
                      PrintPermutation(permutation);
                      continue;
                  }
                  permutation[digitToChange--] = 1;
              }
          }
      
          private void PrintPermutation(int[] permutation)
          {
              for(int i=0;i<3;i++)
              {
                  Console.Write(permutation[i]);
                  Console.Write(" ");
              }
              Console.WriteLine(" ");
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-06-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-13
        • 1970-01-01
        相关资源
        最近更新 更多