简体   繁体   中英

C++ Condensing nested for loops

I have these for loops.

// output all possible combinations
for ( int i1 = 0; i1 <= 2; i1++ )
     {
         for ( int i2 = 0; i2 <= 2; i2++ )
             {
                 for ( int i3 = 0; i3 <= 2; i3++ )
                     {
                         for ( int i4 = 0; i4 <= 2; i4++ )
                             {
                                 for ( int i5 = 0; i5 <= 2; i5++ )
                                     {
                                         for ( int i6 = 0; i6 <= 2; i6++ )
                                             {
                                                 for ( int i7 = 0; i7 <= 2; i7++ )
                                                     {
                                                         //output created words to outFile
                                                         outFile
                                                         << phoneLetters[n[0]][i1]<< phoneLetters[n[1]][i2]
                                                         << phoneLetters[n[2]][i3]<< phoneLetters[n[3]][i4]
                                                         << phoneLetters[n[4]][i5]<< phoneLetters[n[5]][i6]
                                                         << phoneLetters[n[6]][i7]
                                                         << " ";

                                                         if ( ++count % 9 == 0 ) // form rows
                                                             outFile << std::endl;
                                                         }
                                                 }
                                         }
                                 }
                         }
                 }
         }

It looks awful but I'm too much of a newb to know where to begin in regards to condensing them.

Can someone give me a pointer or two so I can make this code a little neater?

You're indexing 0, 1, and 2 on seven levels. This may not be terribly efficient, but how about this:

int i1, i2, i3, i4, i5, i6, i7;
int j;

for (int i = 0; i < 2187; i++)
{
    // 0 through 2186 represent all of the ternary numbers from
    //    0000000 (base 3) to 2222222 (base 3).  The following
    //    pulls out the ternary digits and places them into i1
    //    through i7.

    j = i;

    i1 = j / 729;
    j = j - (i1 * 729);

    i2 = j / 243;
    j = j - (i2 * 243);

    i3 = j / 81;
    j = j - (i3 * 81);

    i4 = j / 27;
    j = j - (i4 * 27);

    i5 = j / 9;
    j = j - (i5 * 9);

    i6 = j / 3;
    j = j - (i6 * 3);

    i7 = j;

    // print your stuff
}

Or, based on user315052's suggestion in the comments:

int d[7];

for (int i = 0; i < 2187; i++)
{
    int num = i;
    for (int j = 6; j >= 0; j--)
    {
        d[j] = num % 3;
        num = num / 3;
    }

    // print your stuff using d[0] ... d[6]]
} 

In the general case, you could use recursion:

template <typename Stream, typename Iterator>
void generateNumbers(Stream& stream, Iterator begin, Iterator end) {
  if (end - begin == 7) {
    for (Iterator p = begin; p < end; p++) {
      stream << phoneLetters[n[*p]][*p];
    }
    stream << " ";
  } else {
    for (*end = 0; *end <= 2; ++*end)
      generateNumbers(stream,begin,end+1);
    if (end - begin == 6)
      stream << std::endl;
  }
}

Which you can call by using either a buffer vector or a plain old C array (both with sufficient size).

For example:

std::vector<int> buf(7,0);
generateNumbers(std::cout,buf.begin(),buf.begin());
// or
int buf2[7];
generateNumbers(std::cout,buf2,buf2);

But if your values are binary, PBrando 's answer is better.

I see James McNellis already commented this solution, but here it is:

void phone_combo(int n[], int i[], int d, ostream &ofile, int &count) {
    if (d == 7) {
        //output created words to outFile
        ofile
        << phoneLetters[n[0]][i[0]]<< phoneLetters[n[1]][i[1]]
        << phoneLetters[n[2]][i[2]]<< phoneLetters[n[3]][i[3]]
        << phoneLetters[n[4]][i[4]]<< phoneLetters[n[5]][i[5]]
        << phoneLetters[n[6]][i[6]]
        << " ";
        if ( ++count % 9 == 0 ) // form rows
            ofile << std::endl;
        }
        return;
    }
    for (i[d] = 0; i[d] <= 2; i[d]++) {
        phone_combo(n, i, d+1, ofile, count);
    }
}

int i[7];
phone_combo(n, i, 0, outFile, count);

There was a response posted earlier that reduced this to a single for loop but it was removed for some reason.

for( int i(0); i!= 2187; ++i )
{
    outFile
    << phoneLetters[n[0]][(i >> 6) & 0x01]<< phoneLetters[n[1]][(i >> 5) & 0x01]
    << phoneLetters[n[2]][(i >> 4) & 0x01]<< phoneLetters[n[3]][(i >> 3) & 0x01]
    << phoneLetters[n[4]][(i >> 2) & 0x01]<< phoneLetters[n[5]][(i >> 1) & 0x01]
    << phoneLetters[n[6]][i & 0x01]
    << ' ';

    if ( ++count % 9 == 0 ) // form rows
        outFile << '\n';
}

This is only going to work if you know the exact number of iterations needed to compute each possible permutation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM