2

So, I've created a matrix like this:

constexpr size_t row = 3, col = 5;

std::vector<std::vector<int>> matrix(row, std::vector<int>(col));

And I'm trying to fill it with user's input. This is the best solution I've got so far:

for (size_t i = 0; i < matrix.size(); i++) 
{

    for (size_t j = 0; j < matrix[i].size(); j++) 
    {
        std::cout << "Matrix[" << i << "][" << j << "] = ";

        std::cin >> matrix[i][j];
    }

    std::cout << "\n";
}

It looks alright, works fine, but there must be a way to achieve this using STL, to make this code less bulky.

So I'm asking for your help with filling my matrix with user's input. Any help will be appreciated!

Thanks.

Michael
  • 548
  • 6
  • 23
  • That looks elegant to me, it's what you'd expect a 2D matrix to be built like. You can obfuscate it further if you want with tricks like generating a list of indices for each size and zipping the two to obtain (X, Y) pairs, but I don't see much help in that. The only improvement I see would be to wrap vector> into a single Matrix class and work with that. – CakePlusPlus Jul 03 '16 at 17:56
  • @AlexM. Or defining operator>> for std::vector and using istream_iterator – Revolver_Ocelot Jul 03 '16 at 17:58

3 Answers3

3

If all you are after is to prettify it..then you can do something like:

  constexpr size_t row = 3, col = 5;
  constexpr size_t total = row * col;
  std::vector<std::vector<int>> matrix(row, std::vector<int>(col));

  int j = -1;
  for (int i = 0; i < total; i++) {
    std::cin >> matrix[(i % col) ? j : ++j][i % col];
  }

And with C++14:

std::for_each(std::begin(matrix), std::end(matrix), [](auto& v) mutable{
        for (auto& e : v) std::cin >> e;
});

You can also do the above with c++11 without the auto type deduction for lambda.

Arunmu
  • 6,837
  • 1
  • 24
  • 46
  • Wow, so `std::for_each` can modify my vector? I only need to add `mutable` before curly braces... Cool, thanks! – Michael Jul 03 '16 at 18:20
0

You can try std::for_each, to make your code smaller. This way you need to define two functions (one for the rows, one for the columns) to initialize your matrix.

SAlex
  • 361
  • 2
  • 10
  • Not sure if that's going to work, `std::for_each` is a non-modifying sequence operation. I can only pass one row by value at a time, which means that I won't be modifying my matrix at all. – Michael Jul 03 '16 at 18:16
  • Nevermind, it will work. I'm just too new to C++, I didn't know about `mutable` keyword... – Michael Jul 03 '16 at 18:24
0

User Input Is Never Easy
There is a lot that may go wrong, and you must always handle it carefully.

The end goal, then, should be to make input reasonable for the end user, and not necessarily “pretty”.

For example:

#include <algorithm>
#include <cctype>
#include <iostream>
#include <iterator>
#include <vector>
#include <sstream>
#include <string>

struct matrix: public std::vector<std::vector<int>> { };

std::istream& operator >> (std::istream& ins, matrix& m)
{
  std::string s;
  std::size_t cols = 0;

  // while input and not a blank line
  while (std::getline(ins, s) and !s.empty())
  {
    // scan one row from the input line
    std::istringstream ss{ s };
    std::vector<int> row;
    std::copy(std::istream_iterator<int>(ss), std::istream_iterator<int>(), std::back_inserter(row));

    // make sure that the source input stream fails if the intermediary fails
    if (ss.fail()) 
    {
      ins.setstate(std::ios::failbit);
      return ins;
    }
    m.emplace_back(row);

    // keep track of maximum number of columns
    cols = std::max(cols,row.size());
  }

  // make sure the matrix has the same number of columns in each row
  for (auto& row : m) row.resize(cols);
  return ins;
}

int main()
{
  matrix m;

  std::cout << "Enter the matrix, one row per line.\n"
               "Press Enter twice when done:\n";
  std::cin >> m;

  auto rows = m.size();
  auto cols = m.size() ? m[0].size() : 0;
  std::cout << "Your matrix has " << rows << " rows and " << cols << " columns.\n";
}

Clearly, this is far from pretty. But it does the Right Thing.

Hope this helps.

Dúthomhas
  • 8,200
  • 2
  • 17
  • 39
  • Please restrain deriving from standard containers. It's not the _right_ thing. – Arunmu Jul 03 '16 at 18:18
  • The _right_ thing according to what standard? You're just being a mindless pedant -- there's nothing wrong with inheriting from a standard container if you don't next try to treat it as something it isn't. http://stackoverflow.com/questions/6806173/subclass-inherit-standard-containers/7302165#7302165 If it makes that much of a difference to you, put it in a namespace or apply private inheritance or use composition or just create a named function. Oh, and don't dynamically allocate standard containers, OK? It indicates _bad design issues_. – Dúthomhas Jul 03 '16 at 20:25