问题
After reading through most of the maps
questions, I eventually got an idea from this link: How to unique my data that are stored in an object which are stored in a vector?
I have a task of storing X
, Y
, Z
coordinates from the user input. To prevent the user from entering duplicated data, I have decided to use map containers as they do not allow duplicated data.
I tested the code out.
I am using X
as the key
and Y as the value
I am able to store X
and Y
via this:
map<int, int> mapp2d;
mapp2d.insert(pair<int, int>(X, Y));
And to access them via this:
map<int, int>::iterator p = mapp2d.begin();
map<int, int>::iterator e = mapp2d.end();
while ( p != mapp2d.end())
{
cout << "X: " << p->first << " Y: " << p->second << endl;
p++;
}
Is it possible to do it for X
, Y
, Z
? Like this:
map<int, int, int> mapp3d
mapp3d.insert(pair<int, int, int>(X, Y, Z))
I tested out the code but i got this errors:
error: wrong number of template arguments (3, should be 2)
error: provided for ‘template<class _T1, class _T2> struct std::pair
Yes, i do know it is illegal for me to do that, but there're no tutorials on how should i do so, and i kind of ran out of ideas, and how can i access them ?
Appreciate you guys for taking a look, thanks in advance.
回答1:
You should store the coordinates together instead of using one coordinate as key:
struct Point
{
int x, y, z;
Point(int x, int y, int z) : x(x), y(y), z(z) {}
};
Then just implement a custom comparator:
struct PointComparator
{
bool operator()(const Point& a, const Point& b)
{
if (a.x < b.x) return true;
if (a.x == b.x && a.y < b.y) return true;
if (a.x == b.x && a.y == b.y && a.z < b.z) return true;
return false;
}
};
And finally, use a set instead of a map (because in your case, values and keys are the same):
#include <set>
std::set<Point, PointComparator> points;
Sets are (just like maps) ordered, by default from low to high values. You need to specify a custom comparator here because the default one that is used if you just do std::set<Point>
is std::less
. This comparator can compare numbers etc, but has no clue how to compare objects of type Point
. The set could therefore not order its elements properly and also not figure out if two elements are identical (which is what you are after). If you do std::set<Point, PointComparator>
, you create a set that uses the logic in PointComparator
to compare its elements.
This example will print "1" and "2":
points.insert(Point(1, 2, 3));
points.insert(Point(1, 2, 3));
points.insert(Point(2, 3, 4));
std::set<Point, PointComparator>::iterator it = points.begin();
while (it != points.end()) {
std::cout << "x = " << it->x << std::endl;
it++;
}
回答2:
Have you considered using a tuple? They can be used for holding more than 2 elements
http://www.cplusplus.com/reference/tuple/tuple/
I guess another possibility if you really have your heart set on using a map is doing something like the below link where your map's values are :
Using find on map<pair, int>
回答3:
I'm not a C++ expert, but I think you should use a set rather than a map, and use a tuple for the values. Sets are normally used for holding unique values (although I'm speaking from Java and Python knowledge rather than C++). Look at set and unordered_set; apparently unordered_set is faster, but set is sorted. Neither of them keep track of the order you put things in, and neither does map, so if you need that then you'll need to find a different solution. And I think tuples can store arbitrary numbers of elements.
回答4:
It's often useful to distinguish between how you store data and how you access it.
For example, you can store the points in a vector, but place a 'uniqueness index' upon them by using, say, a std::set. Here's some standalone code demonstrating the idea:
#include <functional>
#include <iostream>
#include <memory>
#include <set>
#include <vector>
class Point {
public:
Point(int x, int y, int z) : m_x(x), m_y(y), m_z(z) {}
int x() const { return m_x; }
int y() const { return m_y; }
int z() const { return m_z; }
private:
int m_x;
int m_y;
int m_z;
};
bool operator<(const Point & a, const Point & b) {
return (a.x() < b.x()
|| (a.x() == b.x()
&& (a.y() < b.y()
|| (a.y() == b.y()
&& a.z() < b.z()))));
}
class Points {
public:
Points() {}
bool add(Point p) {
if (m_uniqueIndex.count(p) == 0) {
m_points.emplace_back(new Point(p));
m_uniqueIndex.emplace(*m_points.back());
return true;
}
return false;
}
private:
std::set<std::reference_wrapper<Point>> m_uniqueIndex;
std::vector<std::unique_ptr<Point>> m_points;
};
const char * s(bool b) {
return b ? "true" : "false";
}
int main(int argc, char * argv[]) {
Point a(1, 2, 3);
Point b(2, 1, 0);
Point c(-1, 0, 1);
Point a2(1, 2, 3);
Points points;
std::cout << "Adding a: " << s(points.add(a)) << std::endl;
std::cout << "Adding b: " << s(points.add(b)) << std::endl;
std::cout << "Adding c: " << s(points.add(c)) << std::endl;
std::cout << "Adding a2: " << s(points.add(a2)) << std::endl;
}
In my experience, when using spatial data, you always end up wanting to ask questions like: what are this coodinates neighbours? How many things are within some distance of this coordinate, etc. So I'd also recommend that you do some reading-up on k-d trees (for points) and r trees (for shapes).
来源:https://stackoverflow.com/questions/30424050/is-there-anyway-to-store-key-value-value-into-map