需要有关重构深度嵌套代码的帮助

Need help on refactoring a deeply nested code

本文关键字:嵌套 代码 帮助 深度 重构      更新时间:2023-10-16
#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;
}
if(range>i)

为什么不在range处启动i并避免该问题呢 哦,我倒过来说了,但重点是——你可以很容易地将其重构为for条件的一部分。不需要额外的条件。

if(j>i)

为什么不在i启动j呢?

(对其他两个回路重复)

这样就可以去掉一半的嵌套。就循环本身而言,我建议对它们使用提取方法。

您可以做的第一件事是使用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将提高可读性。

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

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;
}

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

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

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

我的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(" ");
    }