views:

187

answers:

6

I tried to print all the possible combination of members of several vectors. Why the function below doesn't return the string as I expected?

#include <iostream>
#include <vector>
#include <fstream>
#include <sstream>
using namespace std;

string EnumAll(const vector<vector<string> > &allVecs, size_t vecIndex, string
        strSoFar)
{
    string ResultString;
    if (vecIndex >= allVecs.size())
    {
        //cout << strSoFar << endl;
        ResultString = strSoFar;
        //return ResultString;
    }
    for (size_t i=0; i<allVecs[vecIndex].size(); i++) {
        strSoFar=EnumAll(allVecs, vecIndex+1, strSoFar+allVecs[vecIndex][i]);
    }
    ResultString = strSoFar; // Updated but still doesn't return the string.
    return ResultString;  

}


int main  ( int arg_count, char *arg_vec[] ) {

    vector <string> Vec1;
          Vec1.push_back("T");
          Vec1.push_back("C");
          Vec1.push_back("A");

    vector <string> Vec2;
          Vec2.push_back("C");
          Vec2.push_back("G");
          Vec2.push_back("A");

    vector <string> Vec3;
          Vec3.push_back("C");
          Vec3.push_back("G");
          Vec3.push_back("T");


     vector <vector<string> > allVecs;

     allVecs.push_back(Vec1);
     allVecs.push_back(Vec2);
     allVecs.push_back(Vec3);




     string OutputString = EnumAll(allVecs,0,"");

     // print the string or process it with other function.
     cout << OutputString << endl;  // This prints nothing why?

     return 0;
}

The expected output is:

TCC
TCG
TCT
TGC
TGG
TGT
TAC
TAG
TAT
CCC
CCG
CCT
CGC
CGG
CGT
CAC
CAG
CAT
ACC
ACG
ACT
AGC
AGG
AGT
AAC
AAG
AAT
+3  A: 

Your function doesn't return anything because your last call doesn't return anything since there's no return and the end of your function.

Edit: One thing that you can do, is to insert your ResultString to a global vector each time before the return. And at the end, all your results will be available in this vector.

Soufiane Hassou
@SH: Thanks for the reply, but I added the return already still it doesn't give result. (See my update).
neversaint
well, this is another issue, the return will be empty anyway, since you didn't initialize ResultString
Soufiane Hassou
I edit my answer, see if it helps you more.
Soufiane Hassou
+3  A: 

You call EnumAll recursively, but you ignore the string that it returns. You have to decide how you are going to aggregate those strings - or what you are going to do with them.

Jonathan Leffler
@JL: Ok. I think I need a vector to aggregate them. But where/how can I do that?
neversaint
Well, is EnumAll going to return a single string, or a vector of strings? If it is a single string, how are you going to separate individual items? A newline? If it is a vector, it makes life easier, probably - except you have to know how to concatenate one vector's worth of strings (the return from the recursive invocation of EnumAll) to the end of the local return value (another vector).
Jonathan Leffler
+1  A: 

Your second return should also accumulate the strSoFar in some way. Something like:

for (size_t i=0; i<allVecs[vecIndex].size(); i++)
{
    strSoFar = EnumAll(allVecs, vecIndex+1, strSoFar+allVecs[vecIndex][i]);
}
ResultString = strSoFar;
return ResultString;
Kyle Walsh
@Kyle: I tried your suggestion, but it still doesn't print. Is there anything I missed from your posting?
neversaint
@neversaint Well I said something "like" that, not exactly that. Also, you should either uncomment the first return statement, or pass the ResultString to the recursive function otherwise your edited code won't do anything.
Kyle Walsh
+1  A: 

The code you provided crashes. In the following line, notice that you will be exceeding the limits of vecIndex. There is no check on it in the loop. Also, in the if condition above, you donot reset the vecIndex either. So you will have an access violation.

strSoFar = EnumAll(allVecs, vecIndex+1, strSoFar+allVecs[vecIndex][i]);

To fix it, either rest vecIndex in the if() or use the following for statement:

for (size_t i=0; i<allVecs[vecIndex].size() && vecIndex < allVecs.size(); i++){...}

Edit: However, this does not give the correct output yet.

Sai Charan
+1  A: 

Your function determines all the correct combinations but they are lost since you do not aggregate them properly.

I see you asked the same question here. I will assume you are now looking for a means to get the output back to the top level so you can handle it from there.

The problem then comes down to how you aggregate the output. You are using a string, but are looking for multiple rows of data. There are infinite answers to this .. here is one using a vector container.

#include <iostream>
#include <vector>
#include <fstream>
#include <sstream>
using namespace std;

void printAll(const vector<string> data);

void EnumAll(const vector<vector<string> > &allVecs, size_t vecIndex, vector<string>&allStr, string strSoFar)
{
    if (vecIndex >= allVecs.size())
    {
      allStr.push_back(strSoFar);
      return;
    }
    for (size_t i=0; i<allVecs[vecIndex].size(); i++)
      EnumAll(allVecs, vecIndex+1, allStr, strSoFar+allVecs[vecIndex][i]);
}


int main  ( int arg_count, char *arg_vec[] ) {

    vector <string> Vec1;
          Vec1.push_back("T");
          Vec1.push_back("C");
          Vec1.push_back("A");

    vector <string> Vec2;
          Vec2.push_back("C");
          Vec2.push_back("G");
          Vec2.push_back("A");

    vector <string> Vec3;
          Vec3.push_back("C");
          Vec3.push_back("G");
          Vec3.push_back("T");


     vector <vector<string> > allVecs;

     allVecs.push_back(Vec1);
     allVecs.push_back(Vec2);
     allVecs.push_back(Vec3);



     vector<string> allStr;
     EnumAll(allVecs,0,allStr,"");

     // print the string or process it with other function.
     printAll(allStr);

     return 0;
}

void printAll(const vector<string> data)
{
  vector<string>::const_iterator c = data.begin();
  while(c!=data.end())
    {
      cout << *c << endl;
      ++c;
    }

}

youngthing
+1  A: 

Here is an alternate solution. This does not expect you to pass anything but the initial vectors:

int resultSize( vector< vector<string> > vector ){
 int x=1;
 for( int i=0;i<vector.size(); i++ )
  x *= vector[i].size();
 return x;
}

vector<string> enumAll(const vector< vector<string> > allVecs )
{
 //__ASSERT( allVecs.size() > 0 );
 vector<string> result;
 if( allVecs.size() == 1 ){
  for( int i=0 ; i< allVecs[0].size(); i++){
   result.push_back( allVecs[0][i] );
  }
  return result;
 }
 for( int i=0; i<allVecs[0].size(); i++ ){
  for( int j=0; j<resultSize( vector< vector<string> >(allVecs.begin()+1, allVecs.end() ) ); j++){
   result.push_back( allVecs[0][i] + enumAll(vector< vector<string> >(allVecs.begin()+1, allVecs.end() ))[j] );//enumAll on each tempVector is called multiple times. Can be optimzed.
  }
 }
}

Advantage of this method: This is very readable in terms of the recursion. It has easily identifiable recursion base step and also the recursion itself. It works as follows: Each iteration of the recursion enumerates all possible strings from n-1 vectors and the current step simply enumerates them.

Disadvantages of this method: 1. enumAll() function is called multiple times returning the same result. 2. Heavy on stack usage since this is not tail recursion.

We can fix (1.) by doing the following, but unless we eliminate tail recursion, we cannot get rid of (2.).

vector<string> enumAll(const vector< vector<string> > allVecs )
{
 //__ASSERT( allVecs.size() > 0 );
 vector<string> result;
 if( allVecs.size() == 1 ){
  for( int i=0 ; i< allVecs[0].size(); i++){
   result.push_back( allVecs[0][i] );
  }
  return result;
 }
 const vector< vector<string> > tempVector(allVecs.begin()+1, allVecs.end() );
 vector<string> tempResult = enumAll( tempVector );// recurse
 int size = resultSize( tempVector );
 cout << size << " " << tempResult.size() << endl;
 for( int i=0; i<allVecs[0].size(); i++ ){
  for( int j=0; j<size; j++){
   result.push_back( allVecs[0][i] + tempResult[j] );
  }
 }
}
Sai Charan