Reputation: 33
#include<bits/stdc++.h>
using namespace std;
int main() {
int i,j;
vector<int> v(100); // defined a vector of size 100
for(i=1;i<=50;i++) {
v[i]=i; // storing the values as we do in 1-d array
}
for(int i=1;i<=50;i++) {
cout<<"index="<<i<<" "<<v[i]<<"\n"; // It will give output similar
// to 1-d array
}
return 0;
}
So this is the case of one dimensional vector where index of vector is integer and the value is also integer. The above code is running fine.
But i want to take the index of a vector as pair (i,j) and the value as an integer.
See the below code for more clarification .
#include<bits/stdc++.h>
using namespace std;
int main() {
int i,j;
vector<pair<int,int>> ve(make_pair(100,100));
//defined a vector of size of indices (100,100)
for(i=1;i<=50;i++) {
for(j=0;j<=50;j++) {
ve[make_pair(i,j)]=2; // Storing value of 2 in all the
// (i,j) indices
}
}
for(int i=1;i<=50;i++) {
for(j=0;j<=50;j++) {
cout<<ve[make_pair(i,j)]<<" ";
// Output should be 2 in all the possible pairs of (i,j)
}
}
return 0;
}
But the above code is not working :(. Please tell me how i can fix this problem.
Upvotes: 3
Views: 5262
Reputation: 2684
Keep it simple
All you need is 1 (One!) C++ line: ...+ Update: Optional macro (the macro is to answer @eneski comment):
std::vector<std::vector<int>> ve(100, std::vector<int>(100, 0)); // Initialize to 0
// Turns [wr(pair)] syntax to [pair.first][pair.second] syntax:
#define wr(pr) (pr).first][(pr).second // Wrapper macro
And than use:
ve[wr(std::make_pair(i, j))] = 35; // For example
int val = ve[wr(std::make_pair(i, j))];
// Or:
ve[i][j] = 70; // For example
val = ve[i][j];
There is no real need to use the wr
wrapper macro. Use ve[i][j]
and if you have somewhere in your code a std::pair p
, use: ve[p.first][p.second]
instead of ve[p]
- Both are the same. Also, it is nonsense to take (i, j)
and to make_pair on-the-fly just to use them again as [i][j]
indexes. If, despite all, one insists on the syntax, than use the wr
wrapper macro.
--
But, in a case of a fixed sequential range, a 2D std::array is a better choice (& you can add the wrapper macro as well, if you insist):
#include <array>
int main()
{
int i = 7, j = 5;
std::array<std::array<int, 100>, 100> ar; // 100 X 100
ar[0].fill(0); ar.fill(ar[0]); // Initialize to 0
ar[i][j] = 35; // For example
return 0;
}
Upvotes: 1
Reputation: 69912
another solution: create your own container by aggregating a standard one.
Extremely simplified example:
#include <vector>
#include <iostream>
struct xy
{
std::size_t x, y;
};
constexpr std::size_t linear_extent(xy _)
{
return _.y * _.x;
}
constexpr std::size_t linear_position(xy _, xy extent)
{
return _.y * extent.x + _.x;
}
template<class T>
struct vector_2d
{
vector_2d(xy size, T x = T())
: extent_(size)
, storage_(linear_extent(extent_), x)
{
}
T& operator[](xy const& _)
{
return storage_[linear_position(_, extent_)];
}
T const& operator[](xy const& _) const
{
return storage_[linear_position(_, extent_)];
}
constexpr auto extent() const { return extent_; }
xy extent_;
std::vector<T> storage_;
};
template<class T>
std::ostream& operator<<(std::ostream& os, vector_2d<T> const& v)
{
const char* sep = " [";
os << "[";
auto extent = v.extent();
for(auto y = std::size_t(0) ; y < extent.y ; ++y)
{
os << sep;
const char* sep2 = " ";
for (auto x = size_t(0) ; x < extent.x ; ++x)
{
std::cout << sep2 << v[{x, y}];
sep2 = ", ";
}
os << " ]";
sep = "\n [";
}
os << " ]";
return os;
}
int main()
{
auto v = vector_2d<int>({5, 5});
v[{1, 3}] = 8;
std::cout << v << std::endl;
}
Upvotes: 1
Reputation: 6240
Are you simply attempting to access 1d vector content as if it was a 2d vector? Perhaps you could use a helper function to convert 2d index into 1d index, for example:
#include <vector>
#include <iostream>
#include <cassert>
template<size_t ROWS, size_t COLS>
size_t convertIndex(size_t row, size_t col)
{
assert(row < ROWS && col < COLS);
return row * COLS + col;
}
int main()
{
std::vector<int> v =
{
0,1,2,3,4,
5,6,7,8,9
};
std::cout << v[convertIndex<2, 5>(1, 3)];
}
This outputs 8
Upvotes: 0
Reputation: 8475
Vectors, like arrays, work only with integer indexes. For a vector vec, the index must be in range 0 <= index < vec.size()
, otherwise it either does not compile (not convertible to unsigned int
) or the behavior is undefined (out of bounds).
You have written
vector<pair<int,int>> ve
Which means that you create a vector that contains pairs, not that it is indexed by pairs.
Now, if you want a two dimensional vector, i.e. a matrix, you should check Boost matrix. You can also implement it yourself, but making it general purpose will take some effort. The basic idea is to convert the pair to an single integer value. The simplest implementation is:
template <class T>
void init_2d(std::vector<T> &vec, std::pair<unsigned, unsigned> coordinates)
{
vec.resize(coordinates.first * coordinates.second);
}
inline unsigned flatten(std::pair<unsigned, unsigned> coordinates,
unsigned num_columns)
{
return coordinates.first * num_columns + coordinates.second;
}
template <class T>
T & get_2d(std::vector<T> & vec,
std::pair<unsigned, unsigned> coordinates,
unsigned num_columns)
{
return vec.at(flatten(coordinates, num_columns));
}
template <class T>
const T & get_2d(const std::vector<T> & vec,
std::pair<unsigned, unsigned> coordinates,
unsigned num_columns)
{
return vec.at(flatten(coordinates, num_columns));
}
and then use it in your code:
int main() {
std::vector<int> ve;
auto dimensions = std::make_pair(100,100);
init_2d(ve, dimensions);
for(int i=1;i<=50;i++) {
for(int j=0;j<=50;j++)
get_2d(ve, {i,j}, dimensions.second) =j;
}
for(int i=1;i<=50;i++) {
for(int j=0;j<=50;j++)
std::cout << get_2d(ve, {i,j}, dimensions.second) <<" ";
std::cout << '\n';
}
return 0;
}
But, instead of reimplementing existing code, you should prefer to use boost matrix. If you are trying to learn how a matrix can be implemented (which is a very good idea), then go on and try to convert the above functions+vector into a class, and put the dimensions
pair into that class. Having a class, for a matrix, is better than to use separate functions. It is easier to maintain invariants for a class than for separate functions.
Note: you can use std::map<std::pair<int, int>>
instead, but it will be more difficult to iterate over it and it will be much slower. If it makes your code clearer, using std::map
is a good idea, but it is not clear cut whether std::map<pair<...>>
is easier to work with than with std::vector
+ _2d functions.
Upvotes: 2
Reputation: 1665
I would suggest you to use map
instead.
Operator []
for map takes key_type
as parameter which is a container which means you can use pair
object as index (called key in map), however Operator [] for vetor takes size_type
as parameter which is an unsigned integer.
Your code could look like the following:
map< pair<int, int>, int > notVector;
for(i=0;i<=50;i++)
for(j=0;j<=50;j++)
notVector[make_pair(i,j)]=2; // Storing value of 2 in all the (i,j) indices
for(i=0;i<=50;i++)
for(j=0;j<=50;j++)
cout<<notVector[make_pair(i,j)]<<" ";
Upvotes: 1