Reading a Matrix txt file and storing as an array

前端 未结 5 1529
名媛妹妹
名媛妹妹 2020-12-03 15:34

I\'m currently writing a Simulated Annealing code to solve a traveling salesman problem and have run into difficulties with storing and using my read data from a txt file. E

相关标签:
5条回答
  • 2020-12-03 16:03

    Reference from my blog: http://www.topbug.net/blog/2013/01/10/load-a-matrix-from-an-ascii-format-file/

    This code snippet has higher fault tolerance instead of assuming everything is well formatted.

    #include <istream>
    #include <string>
    #include <sstream>
    #include <vector>
    
    // load matrix from an ascii text file.
    void load_matrix(std::istream* is,
            std::vector< std::vector<double> >* matrix,
            const std::string& delim = " \t")
    {
        using namespace std;
    
        string      line;
        string      strnum;
    
        // clear first
        matrix->clear();
    
        // parse line by line
        while (getline(*is, line))
        {
            matrix->push_back(vector<double>());
    
            for (string::const_iterator i = line.begin(); i != line.end(); ++ i)
            {
                // If i is not a delim, then append it to strnum
                if (delim.find(*i) == string::npos)
                {
                    strnum += *i;
                    if (i + 1 != line.end()) // If it's the last char, do not continue
                        continue;
                }
    
                // if strnum is still empty, it means the previous char is also a
                // delim (several delims appear together). Ignore this char.
                if (strnum.empty())
                    continue;
    
                // If we reach here, we got a number. Convert it to double.
                double       number;
    
                istringstream(strnum) >> number;
                matrix->back().push_back(number);
    
                strnum.clear();
            }
        }
    }
    
    // example
    #include <fstream>
    #include <iostream>
    
    int main()
    {
        using namespace std;
    
        // read the file
        std::ifstream is("input.txt");
    
        // load the matrix
        std::vector< std::vector<double> > matrix;
        load_matrix(&is, &matrix);
    
        // print out the matrix
        cout << "The matrix is:" << endl;
        for (std::vector< std::vector<double> >::const_iterator it = matrix.begin(); it != matrix.end(); ++ it)
        {
            for (std::vector<double>::const_iterator itit = it->begin(); itit != it->end(); ++ itit)
                cout << *itit << '\t';
    
            cout << endl;
        }
    
        return 0;
    }
    
    0 讨论(0)
  • 2020-12-03 16:05

    You probably want something simpler, like this:

    std::vector<std::vector<std::string> > LoadCities(const std::string &filename)
    {
        using namespace std;
    
        ifstream file;
        file.open(filename, ios::in | ios::out);
    
        if(!file.is_open()) {
            // error
            return vector<vector<double> >();
        }
    
        vector<vector<double> > data;
        string line;
    
        while(!std::getline(file, line, '\n').eof()) {
            istringstream reader(line);
    
            vector<double> lineData;
    
            string::const_iterator i = line.begin();
    
            while(!reader.eof()) {
                double val;
                reader << val;
    
                if(reader.fail())
                    break;
    
                lineData.push_back(val);
            }
    
            data.push_back(lineData);
        }
    
        return data;
    }
    

    Basically you use streams to input the data. I'm probably doing something wrong (I have never dealt with iostreams ;P) but this should give you the general idea of how to structure a matrix reader.

    0 讨论(0)
  • 2020-12-03 16:06

    How about this? (KISS solution)

    void LoadCities() {
      int x, y;
      ifstream in("Cities.txt");
    
      if (!in) {
        cout << "Cannot open file.\n";
        return;
      }
    
      for (y = 0; y < 15; y++) {
        for (x = 0; x < 15; x++) {
          in >> distances[x][y];
        }
      }
    
      in.close();
    }
    

    Works for me. Might not be that complex and perhaps isn't very performant, but as long as you aren't reading a 1000x1000 array, you won't see any difference.

    0 讨论(0)
  • 2020-12-03 16:10

    Here is how I would load/save it:

    #include <iostream>
    #include <fstream>
    #include <string>
    
    int width = 0;
    int height = 0;
    double **distances;
    
    void WriteDouble( std::ofstream &stream, double toWrite )
    {
        char buffer[8];
        memcpy( buffer, &toWrite, 8 );
        stream.write( buffer, 8 );
    }
    
    void WriteInt( std::ofstream &stream, int toWrite )
    {
        char buffer[4];
        memcpy( buffer, &toWrite, 4 );
        stream.write( buffer, 4 );
    }
    
    double ReadDouble( std::ifstream &stream )
    {
        double d = 0;
        stream.read( (char *)&d, 8 );
        return d;
    }
    
    int ReadInt( std::ifstream &stream )
    {
        int i = 0;
        stream.read( (char *)&i, 4 );
        return i;
    }
    
    void Save()
    {
        std::ofstream stream( "cities", std::ios::out | std::ios::binary );
    
        if( !stream.good() ) {
            throw std::exception( "Error opening stream" );
        }
    
        WriteInt( stream, width );
        WriteInt( stream, height );
    
        for( int x = 0; x < width; x++ ) {
            for( int y = 0; y < height; y++ ) {
                WriteDouble( stream, distances[x][y] );
            }
        }
    
        stream.close();
    }
    
    void Load()
    {
        std::ifstream stream( "cities", std::ios::in | std::ios::binary );
    
        if( !stream.good() ) {
            throw std::exception( "Error opening stream" );
        }
    
        width = ReadInt( stream );
        height = ReadInt( stream );
    
        distances = new double *[width];
    
        for( int i = 0; i < width; i++ ) {
            distances[i] = new double[height];
        }
    
        for( int x = 0; x < width; x++ ) {
            for( int y = 0; y < height; y++ ) {
                distances[x][y] = ReadDouble( stream );
            }
        }
    
        stream.close();
    }
    
    void RunSaveTest()
    {
        width = 15;
        height = 15;
    
        distances = new double *[width];
    
        for( int i = 0; i < width; i++ ) {
            distances[i] = new double[height];
        }
    
        for( int x = 0; x < width; x++ ) {
            for( int y = 0; y < height; y++ ) {
                distances[x][y] = (double)x / (double)( y + 1 );
                std::cout << distances[x][y] << std::endl;
            }
        }
    
        Save();
    }
    
    void RunLoadTest()
    {
        Load();
    
        for( int x = 0; x < width; x++ ) {
            for( int y = 0; y < height; y++ ) {
                std::cout << distances[x][y] << std::endl;
            }
        }
    }
    
    int main()
    {
        RunSaveTest();
        // RunLoadTest();
    
        return 0;
    }
    
    0 讨论(0)
  • 2020-12-03 16:15

    Does it even compile? I get ~7 errors. A sample:

    strtok(cities, "\n");

    strtok()'s first argument is a char * and not a std::string.

    Does this help?

    void LoadCities()
    {
      std::vector<double> f((std::istream_iterator<double>
           (std::ifstream("city.txt"))), /* replace filename with your own */
        (std::istream_iterator<double>()));
      if (!f.empty()) {
        std::cout << f.size() << "\n";
        /* print an arbitrary data point with 2 places of decimal */
        std::cout << std::setprecision(2) << f[ 0 ] << std::endl; 
    
      }
    }
    

    Working with matrices doesn't mean you need to have a multidimensional array. Especially, with 2D arrays. Of course it's easier to read and write ;)

    0 讨论(0)
提交回复
热议问题