动态更改嵌套for循环顺序

时间:2015-06-02 07:05:56

标签: c++ for-loop dynamic

我有一个代表特殊文件格式的类。它存储3D空间的离散化数据。我想在屏幕上打印数据。但问题是,我必须以给定的任意顺序打印数据。

我的班级是这样的:

class MyFile
{
    public:
        // ...
        enum SEQUENCE
        {
            SEQ_I       = 200,
            SEQ_J       = 201,
            SEQ_K       = 202
        };
        enum INCREMENT
        {
            PLUS        = 300,
            MINUS       = 301
        };
        double GetVariable(uint64_t i, uint64_t j, uint64_t k) const;
        std::vector<SEQUENCE>  Sequences;
        std::vector<INCREMENT> Increments;
        friend std::ostream & operator<<(std::ostream & os, const MyFile & mf);
        // ...
    private:
        // ...
        std::vector<double> Data;
        // ...
}

我这样用:

MyFile myfile;
// ...
// Load some data to "myfile".
// ...
myfile.Sequences.push_back(MyFile::SEQUENCE::SEQ_J);
myfile.Sequences.push_back(MyFile::SEQUENCE::SEQ_I);
myfile.Sequences.push_back(MyFile::SEQUENCE::SEQ_K);
myfile.Increments.push_back(MyFile::INCREMENT::MINUS);
myfile.Increments.push_back(MyFile::INCREMENT::MINUS);
myfile.Increments.push_back(MyFile::INCREMENT::PLUS);
std::cout << myfile;

上面提到的for循环就是这个方法:

std::ostream & operator<<(std::ostream & os, const MyFile & mf)
{
    // The loop variables.
    uint64_t    InnerMin            = 0;
    uint64_t    MiddlMin            = 0;    // I spelled it "middl" to make
    uint64_t    OuterMin            = 0;    // the all variable names same length.
    uint64_t    InnerMax            = 0;
    uint64_t    MiddlMax            = 0;
    uint64_t    OuterMax            = 0;
    uint64_t    InnerIndex          = 0;
    uint64_t    MiddlIndex          = 0;
    uint64_t    OuterIndex          = 0;
    uint64_t    *i                  = &InnerIndex;
    uint64_t    *j                  = &MiddlIndex;
    uint64_t    *k                  = &OuterIndex;
    int8_t      InnerIncrement      = +1;
    int8_t      MiddlIncrement      = +1;
    int8_t      OuterIncrement      = +1;

    // Find out the variable of the out-most loop.
    switch (mf.Sequences[0])
    {
        default:
        case MyFile::SEQUENCE::SEQ_I:
            i           = &OuterIndex;
            OuterMin    = mf.IndexIMin;
            OuterMax    = mf.IndexIMax;
            break;
        case MyFile::SEQUENCE::SEQ_J:
            j           = &OuterIndex;
            OuterMin    = mf.IndexJMin;
            OuterMax    = mf.IndexJMax;
            break;
        case MyFile::SEQUENCE::SEQ_K:
            k           = &OuterIndex;
            OuterMin    = mf.IndexKMin;
            OuterMax    = mf.IndexKMax;
            break;
    }
    break;
    switch (mf.Increments[0])
    {
        case MyFile::INCREMENT::PLUS:
            OuterIncrement = +1;
            break;
        case MyFile::INCREMENT::MINUS:
            OuterIncrement = -1;
            break;
    }
    break;

    // The middle loop.
    switch (mf.Sequences[1])
    {
        case MyFile::SEQUENCE::SEQ_I:
            i           = &MiddlIndex;
            MiddlMin    = mf.IndexIMin;
            MiddlMax    = mf.IndexIMax;
            break;
        default:
        case MyFile::SEQUENCE::SEQ_J:
            j           = &MiddlIndex;
            MiddlMin    = mf.IndexJMin;
            MiddlMax    = mf.IndexJMax;
            break;
        case MyFile::SEQUENCE::SEQ_K:
            k           = &MiddlIndex;
            MiddlMin    = mf.IndexKMin;
            MiddlMax    = mf.IndexKMax;
            break;
    }
    break;
    switch (mf.Increments[1])
    {
        case MyFile::INCREMENT::PLUS:
            MiddlIncrement = +1;
            break;
        case MyFile::INCREMENT::MINUS:
            MiddlIncrement = -1;
            break;
    }

    // The inner loop.
    switch (mf.Sequences[2])
    {
        case MyFile::SEQUENCE::SEQ_I:
            i           = &InnerIndex;
            InnerMin    = mf.IndexIMin;
            InnerMax    = mf.IndexIMax;
            break;
        case MyFile::SEQUENCE::SEQ_J:
            j           = &InnerIndex;
            InnerMin    = mf.IndexJMin;
            InnerMax    = mf.IndexJMax;
            break;
        default:
        case MyFile::SEQUENCE::SEQ_K:
            k           = &InnerIndex;
            InnerMin    = mf.IndexKMin;
            InnerMax    = mf.IndexKMax;
            break;
    }
    break;
    switch (mf.Increments[2])                   // The third (inner) increment.
    {
        case MyFile::INCREMENT::PLUS:
            InnerIncrement = +1;
            break;
        case MyFile::INCREMENT::MINUS:
            InnerIncrement = -1;
            break;
    }

    // Run the loop.
    for             (uint64_t OuterIndex=OuterMin; OuterIndex<=OuterMax; OuterIndex += OuterIncrement)
    {
        for         (uint64_t MiddlIndex=MiddlMin; MiddlIndex<=MiddlMax; MiddlIndex += MiddlIncrement)
        {
            for     (uint64_t InnerIndex=InnerMin; InnerIndex<=InnerMax; InnerIndex += InnerIncrement)
            {
                os << GetVariable(*i, *j, *k) << "\t";
            }
        }
        os << std::endl;
    }

    return os;
}

这是操纵循环次序的正确方法吗?我发现我实施的方式太长而且复杂。有没有更好的方法呢?

1 个答案:

答案 0 :(得分:1)

改进代码的最简单方法是创建一个辅助函数getNextCoordinate,它接受​​一个坐标和顺序的元组(三元组),以给定的顺序返回下一个元组。加函数getInitialCoordinates,给出给定订单的初始坐标。