无论如何都要将键,值,值存储到地图中

时间:2015-05-24 13:29:34

标签: c++ dictionary containers duplicate-removal

在阅读了大多数maps个问题之后,我最终从这个链接中得到了一个想法:How to unique my data that are stored in an object which are stored in a vector?

我的任务是从用户输入中存储XYZ坐标。为了防止用户输入重复数据,我决定使用地图容器,因为它们不允许重复数据。

我测试了代码。

我使用X作为key而Y作为value

我可以通过以下方式存储XY

map<int, int> mapp2d;
mapp2d.insert(pair<int, int>(X, Y));

通过以下方式访问它们:

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++; 
}

是否可以为XYZ执行此操作?像这样:

map<int, int, int> mapp3d
mapp3d.insert(pair<int, int, int>(X, Y, Z))

我测试了代码,但是我遇到了这个错误:

error: wrong number of template arguments (3, should be 2)
error: provided for ‘template<class _T1, class _T2> struct std::pair

是的,我确实知道这样做对我来说是违法的,但是我没有关于如何这样做的教程,我有点想法,我怎么能访问它们?

感谢你们一起来看看,先谢谢。

4 个答案:

答案 0 :(得分:4)

您应该将坐标存储在一起,而不是将一个坐标用作关键字:

struct Point
{
    int x, y, z;

    Point(int x, int y, int z) : x(x), y(y), z(z) {}
};

然后只需实现一个自定义比较器:

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;
    }
};

最后,使用set而不是地图(因为在您的情况下,值和键是相同的):

#include <set>
std::set<Point, PointComparator> points;

默认情况下,从低值到高值设置(就像地图一样)。您需要在此处指定自定义比较器,因为如果您执行std::set<Point>,则使用的默认比较器为std::less。这个比较器可以比较数字等,但不知道如何比较Point类型的对象。因此,该集合可能无法正确排序其元素,也无法确定两个元素是否相同(这就是您所追求的)。如果您执行std::set<Point, PointComparator>,则会创建一个使用PointComparator中的逻辑来比较其元素的集合。

此示例将打印“1”和“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++;
}

答案 1 :(得分:1)

你考虑过使用元组吗?它们可用于容纳2个以上的元素

http://www.cplusplus.com/reference/tuple/tuple/

我想如果你真的已经开始使用地图,那么另一种可能性就是做下面的链接,你的地图的值是:

Using find on map<pair, int>

答案 2 :(得分:0)

我不是C ++专家,但我认为你应该使用set而不是map,并使用元组作为值。集合通常用于保存唯一值(虽然我说的是Java和Python知识,而不是C ++)。看看set和unordered_set;显然unordered_set更快,但是set已经排序。他们都没有跟踪你放入的顺序,也没有映射,所以如果你需要,那么你需要找到一个不同的解决方案。我认为元组可以存储任意数量的元素。

答案 3 :(得分:0)

区分存储数据的方式和访问方式通常很有用。

例如,您可以将点存储在矢量中,但可以放置一个唯一性指数&#39;通过使用std :: set来使用它们。这里有一些展示这个想法的独立代码:

#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;
}

根据我的经验,当使用空间数据时,你总是想要提出这样的问题:这个邻居是什么?在这个坐标的某个距离内有多少东西等等。所以我还建议您在k-d trees(对于点)和r trees(对于形状)进行一些阅读。< / p>