tags:

views:

122

answers:

5

Hi everyone, I am having trouble "undoing" this method, that dumps essentially a matrix of numbers of variable size into a text file:

void vectorToFile(char *name, vector<vector<double>>* a){
    FILE* fp = fopen(name, "w");
    for(int i=0;i<a->size();i++){
        for(int j=0;j<a->at(i).size();j++){
            fprintf(fp, "%f ", a->at(i).at(j));
        }
        fprintf(fp, "\n");
    }
    fclose(fp);
}

I am having trouble implementing the reverse:

vector<vector<double>> fileToVector(char *name){ ??? }

I am guaranteed that the numbers in the file form a "rectangle", i.e. the sizes of inner vectors are all equal, but I don't know how to figure out the number of entries per row, and the number of columns.

Can anyone point me in the right direction? Every example I found so far implements something much easier, with hardcoded size, or sizes given in first row (which I cannot afford to do unfortunately)

A: 

You can read lines, split using the separator you have, then parse to numbers. You can use getline to read lines as strings and you won't need to know the exact number.

Soufiane Hassou
+1  A: 

It would be easier if you used C++ I/O instead of C I/O. I'd suggest using ifstream to read in the file and use getline() to read each line. Each line is then the numbers that are supposed to go in a vector. Probably the easiest way to parse the string would be to use stringstream. You can then parse each double out and push_back() it onto the vector, so you won't have to care about the size of the vectors. I'd also suggest using std::string instead of char* wherever you can (though for file names, you generally end up having to use c_str() on the them anyway since the file I/O stuff always seems to take const char* instead of std::string).

Jonathan M Davis
+5  A: 

I'm new at C++ so I'm not sure if this is a good approach or not, but I would open the file, read in the input line by line, parsing each line as I read it. Here's some example code (untested, uncompiled):

#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>

std::vector<std::vector<double> > fileToVector(const char *name)
{
    std::vector<std::vector<double> > result;
    std::ifstream input (name);
    std::string lineData;

    while(getline(input, lineData))
    {
        double d;
        std::vector<double> row;
        std::stringstream lineStream(lineData);

        while (lineStream >> d)
            row.push_back(d);

        result.push_back(row);
    }

    return result;
}
dreamlax
worked perfect, thank you sir!
karpathy
Great answer for a newbie, `+1` from me. The only thing I would add is that you check whether the streams actually ever reached EOF before you close them: `if( !lineStream.eof() ) throw inputError("Dammit!");` or better yet, to not to be thrown off by trailing whitespaces `if( !(lineStream >> std::ws).eof() ) throw inputError("Dammit!");`.
sbi
A: 

Is there any particular reason to use the vector > instead of using just double** and using new double[] to allocate the array and each sub-element? My guess is that the array can be dynamically resized at runtime, but if the array is allocated only once, using double** is bound to be much more efficient than iterating over a vector.

In any case, the solution to your problem is to dump the bounds of the array up-front in the file and read it back...

Atul
This isn't very good advice. A vector provides a lot of added benefits (takes care of memory management, provides iterators for use with many of the algorithms in `<algorithm>`, provides bounds-checking if you use `at()`, etc.). Performance should not really be a consideration at this point.
dreamlax
@Atul: just to answer the question you stated, that is whether is there any particular reason to use vector instead of c-style array - the main reason is that OP is asking in context of C++, not C.
erjot
Iterating over a `vector` is likely to be nearly as efficient if not exactly as efficient as iterating overy dynamic arrays. Odds are that the iterators for a `vector` are pointers anyway (at least in release mode), though that's implementation-dependent. Also, using `push_back()` is going to be more efficient than continually resizing the array yourself as you add more elements to it. Regardless, the file I/O costs would drown any performance differences between iterating over a dynamic array and a `vector`. Also, using vectors is going to result in more maintainable code than using arrays.
Jonathan M Davis
A: 

You can try more C++ish approach:

void vectorToFile(std::vector<double> const& vec, std::string const& filename) {
    std::ofstream file(filename);
    if(file.good()) {
        file.flags(std::ios::fixed);
        std::copy(vec.begin(), vec.end(), std::ostream_iterator<double>(file));
    } else {
        // throw error or sth
    }
    file.close();
}

If you want to save as binary file, you can use ostream_binary_iterator like this one - http://bit.ly/9JAxdp:

void vectorToFile(std::vector<double> const& vec, std::string const& filename) {
    std::ofstream file(filename, std::ios::binary);
    if(file.good()) {
        file.flags(std::ios::fixed);
        std::copy(vec.begin(), vec.end(), ostream_binary_iterator<double>(file));
    } else {
        // throw error or sth
    }
    file.close();
}
erjot