0

How do I add two matrices of String type? The user will not enter the number of rows or columns. The user will enter the array only. For example, for the input [5 4-1; 2 1 4] + [3 -5 2.5; 1 2 3], the output should be [8 -1 1.5; 3 3 7] whats the error in stof function and the add? this is my code:

//define a stm fucntion to convert string to matrix
vector <vector <float> > stm(string mat1)
{
    //now let us build the matrix1 by iterating over the string mat1
    //we will break the string over the point where we ";"
    vector <vector <float> > matrix1;
    int index1 = 0;
    for (float i = 0; i < mat1.length(); i++)
    {
        string temp = " ";
        while (mat1[i] != ';')
        {
            temp += mat1[i];
            //now the temp string contains the elements of first row
            //now we will break this at point where we get " " (spaces)
            for (float j = 0; j < temp.length(); j++)
            {
                string num1;
                int index2 = 0;
                while (temp[j] != ' ')
                {
                    num1 += temp[j];
                    //ntf is number to be filled at that position
                    j++;
                }
                float ntf = stof(num1);
                matrix1[index1][index2] = ntf;
                index2++;
            }
            i++;
        }
        index1++;
    }
    return matrix1;
}

int main()
{
    string mat1; cin >> mat1;
    string mat2; cin >> mat2;
    vector <vector <float> > matrix1, matrix2;
    matrix1 = stm(mat1);
    matrix2 = stm(mat2);
    //now let us write a code to add the two matrices;
    vector <float> add;
    for (float i = 0; i < matrix1.size(); i++)
    {
        for (float j = 0; j < matrix1[0].size(); j++)
        {
            add[i][j] = matrix1[i][j] + matrix2[i][j];
        }
    }
    for (float i = 0; i < add.size(); i++)
    {
        for (float j = 0; j < add[0].size(); j++)
        {
            cout << add[i][j] << " ";
        }
        cout << endl;
    }
    return 0;

this is an example input

 [5 4 -1;3 2 1]+[1 2 3;5 4 8]

output

[6 6 2;8 6 9]

1 Answers1

1

I will present one possible solution (out of 42 million options :-)

The idea is to use an Object Oriented approach. So, a class with data and methods.

The data is the required vector of vector of float. And the methods are extraction and addition. For debug purposes, there is also an overwrite of the inserter operator.

Please note: The tricky part is parsing the input string. Especially with white spaces that could be everywhere. For ease of use, I defined a regex for a float value. The regex_token_iterator will extract the sub matches and copy those into a column. And this until the next ";". Looks complex, but is easy to understand in the end.

I put many comments in the code, which makes it a little bit lengthy. Anyway, it will help to understand better.

The main function will look very simple then . . .

EDIT:

Based on the recomendation of David C. Rankin, I updated the source code:

  • Modify variable names to make them more readable
  • Changed base data type from float to double
  • Add more white spaces and line breaks for a better text structure
  • Put in more comments
  • New size check for addition operator
#include <iostream>
#include <sstream>
#include <string>
#include <algorithm>
#include <regex>

// Our test data (raw string) . We could of course also read from a file or from std::cin or any istream
std::istringstream testData(
R"#(   [   1 2    3 ; 4 5 6 7  ]
[   7  8   9;    10  11 12]
)#");


struct Matrix
{
    // The data of our matrix
    std::vector<std::vector<double>> data{};

    // Overloading the extractor operator >> for our Matrix class
    friend std::istream& operator >> (std::istream& is, Matrix& m) {
        // Read a complete line
        std::string line; 
        getline(is, line);

        // Define a regex that matches any double number
        std::regex re("([-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?)");

        // Set iterators. 
        // "Start" will be set to begin() or one past the end of the next semicolon 
        std::string::iterator start = line.begin(); 
        // Position of semincolon or end()
        std::string::iterator posSemicolon{};

        // Read all rows and columns
        do {
            // Set the end iterator for this loop run to the position of the semicolon (or end() )
            posSemicolon = std::find(start, line.end(), ';');

            // Add a new row
            m.data.emplace_back(std::vector<double>());

            // Read a complete line with doubles and put that as column values in the current row
            std::transform(
                std::sregex_token_iterator(start, posSemicolon, re, 1), // Search for text that matches the regex
                std::sregex_token_iterator(),                           // Search until the end (posSemicolon)
                std::back_inserter(*(std::prev(m.data.end()))),         // Put this data into the columns of the current row 
                // Convert the string matched by the regex, into a double
                [](const std::string& stringAsDouble) -> double { return stod(stringAsDouble); }
            );   

            // In case there is more input, 
            if (posSemicolon != line.end()) {
                // then continue tokenizing in the next loop run past the semicolon 
                start = posSemicolon + 1;
            }
        } while (posSemicolon != line.end());
        return is;
    }

    // For debug output purposes. Copy the data of the matrix to std::cout
    friend std::ostream& operator << (std::ostream & os, const Matrix & m) {
        std::for_each(
            m.data.begin(),                           // Iterate over all rows
            m.data.end(), 
            [&os](const std::vector<double> & row) {  // Do for all rows 
                std::copy(                            // Copy data to ostream (print)
                    row.begin(),                      // Iterate ove all columns for this row  
                    row.end(), 
                    std::ostream_iterator<double>(os, " ")); // Print
                std::cout << '\n';                    // Line break after printing a row
            }  
        );
        return os;
    }

    // Overload of the addition operator
    friend Matrix operator +(Matrix & m1, Matrix & m2) {
        // Define an empty matrix
        Matrix result{};

        // To be on the safe side, we will resize the destination matrix size 
        // to maximum values of both matrices
        // Get the max number of rows ofrom both m1 and m2
        const size_t maxRowSize = std::max(m1.data.size(), m2.data.size());

        // Set number of rows in resulting Matrix
        result.data.resize(maxRowSize);

        // Get the maximum number of columns in any of the 2 metrices m1 or m2
        const size_t maxColumnSize = std::max(
            std::max_element(
                m1.data.begin(),    // Iterate over all rows of Matrix m1
                m1.data.end(), 
                [](const std::vector<double> & dv1_1, const std::vector<double> & dv1_2) {
                    return dv1_1.size() < dv1_2.size(); 
                }
            )->size(),
            std::max_element(
                m2.data.begin(),   // Iterate over all rows of Matrix m1
                m2.data.end(), 
                [](const std::vector<double> & dv2_1, const std::vector<double> & dv2_2) {
                    return dv2_1.size() < dv2_2.size(); 
                }
            )->size()
        );

        // Iterate over all matrix elements
        // For all rows 
        for (size_t row = 0; row < maxRowSize; ++row) {

            // Resize the the number of columns in the target matrix
            result.data[row].resize(maxColumnSize);

            // Now iterate over all columns in that row
            for (size_t col = 0; col < maxColumnSize; ++col) {

                // And add the values. First check for valid row and column indices
                double m1Value = ((row < m1.data.size()) && (col < m1.data[row].size())) ? m1.data[row][col] : 0.0;
                double m2Value = ((row < m2.data.size()) && (col < m2.data[row].size())) ? m2.data[row][col] : 0.0;
                result.data[row][col] = m1Value + m2Value;
            }
        }
        return result;
    }
};

int main()
{
    // Define some matrices
    Matrix m1, m2, m3;

    // Read the test data. You can also read from std::cin or from a file
    testData >> m1 >> m2;

    // Add the Matrices
    m3 = m1 + m2;

    // Show result
    std::cout << "Matrix 1:\n" << m1 << "\nMatrix 2:\n" << m2 << "\nMatrix3 = Matrix1 + Matrix2:\n" << m3;

    return 0;
}
Armin Montigny
  • 7,879
  • 3
  • 11
  • 29
  • 1
    Why not `[](const std::string& str) -> float { return stof(str); }` to avoid the shadowing of `s` (on lines `22` & `33`)? Also a note about using `double` instead of `float` in any circumstance where precision is needed. (but good job with the approach) – David C. Rankin Jul 06 '19 at 02:56
  • 1
    Additionally, adequate spacing would greatly help the readability of your code. Is there really a need to put multiple declarations on a single line? `std::string::iterator start = s.begin(); std::string::iterator posSemicolon{};` or to have lines sprawl for `221` characters? – David C. Rankin Jul 06 '19 at 03:10
  • @David. Thank you for the recommendations. I updated the code. @All; Davids comments refer to old code that is no longer visible. – Armin Montigny Jul 06 '19 at 07:02