【问题标题】:std::map: Use only part of keytype for comparison and findingstd::map: 仅使用 keytype 的一部分进行比较和查找
【发布时间】:2015-03-09 11:36:49
【问题描述】:

我有一个映射,它使用某些数据类型 KT 的 pairs 作为映射到矩阵类型的键,即 sth。喜欢

std::map<std::pair<KT,KT>, MatType, PairCompare>

为了比较我只需要pair的第一个元素,所以PairCompare很简单

struct PairCompare
{
    bool operator()(const std::pair<KT,KT>& lhs,const std::pair<KT,KT>& rhs) const
    {return lhs.first<rhs.first;}
};

然而,我想将整个对用作键,因为在遍历地图时我经常需要操作中的第二个元素。

有时,我还需要查找仅基于单个 KT 的地图条目。当然,我应该在 find() 例程中使用一对 KT,但我想避免创建一个虚拟的 KT 对,因为我必须这样做很多次并且可能会变得昂贵。我想使用类似的东西

std::map<std::pair<KT,KT>, MatType, PairCompare> mymap;
KT mykey = // ... some implementation of KT;

// fill map

auto it = mymap.find(mykey); // <- will not work of course, but what I would like to use
auto it = mymap.find(std::pair<KT,KT>(mykey,mykey)); // <- what I am using so far (creating a dummy pair)

Mykey 通常可以同时是左值和右值(在我的应用程序中)。

有没有办法定义一种不同类型的键,它包含两个 KT 实例并且只使用一个用于地图排序,并且还可以通过 单个 直接工作的 KT 查找?可以用一些特殊的比较对象来完成吗?也许还有一种巧妙的方法可以完全使用 KT 对作为 Key,但仍然可以在地图迭代中访问第二个 KT?

感谢您的帮助!

P.S.:准确地说,我使用的是 KT

typedef std::vector<int> KT

【问题讨论】:

  • “可能会变得昂贵”。您是否测量过它对于您的用例来说太慢了?
  • 这不是很糟糕,但它确实增加了我想删除的开销。当 KT 是一个相当长的向量(比如 10 左右)时,这当然会更明显。
  • 但是...如果该对的第二部分不用于比较,则表示 Key1 (A,B) 和 Key2(A,C) 相同(关于比较)...比意味着只有 Key1 OR Key2 可以在地图中......所以你可以使用 (A,X) 来查询地图......并添加一个额外的步骤来检查密钥是否是你所期望的.
  • 你真的想要std::map&lt;KT, std::pair&lt;KT, MatType&gt;&gt;吗?看起来您将一对定义为键,然后尝试以某种方式撤消该定义并将键视为只是一个单个元素。
  • std::map&lt;std::pair&lt;std::vector&lt;int&gt;, std::vector&lt;int&gt;&gt;, MatType&gt; 必须是有史以来最小的本地对象。将两个向量作为键会强制每个比较操作需要大量的内存查找,许多潜在的缓存未命中。

标签: c++ c++11 dictionary stl


【解决方案1】:

您的问题是您将密钥视为“一对 X,Y”。把键想象成“一个支持这个和那个操作的对象”:

template<typename K1, typename K2>
class Key
{
    K1 v1_;
    boost::optional<K2> v2_;
public:
    Key(K1 v1): v1_{ std::move(v1) }, v2_{} {}
    Key(K1 v1, K2 v2): v1_{ std::move(v1) }, v2_{ std::move(v2) } {}
    bool operator==(const Key<K1,K2>& other)
    {
        if(!v2_ || !other.v2_)
            return v1_ == other.v1_;
        return std::tie(v1_, *v2_) == std::tie(other.v1_, *other.v2_);
    }
    // implement other comparisons, as required
};

using KeyType = Key<int,std::string>;
std::map<KeyType, MatType> YourMap;
// add key comparable by first element:
YourMap[KeyType{0}] = MatType{}; // match KeyType{0, "any string"}
// add key comparable by both elements:
YourMap[KeyType{1, "test"}] = MatType{}; // match KeyType{1, "test"}

在此处尝试将密钥强制为一对会使问题复杂化。

【讨论】:

  • 这将是我对 OP 的建议。非常好。
  • 这是一个非常有趣的解决方案!事实上,我虽然从 KT 定义了一些包含另一个 KT 的派生类,但使用 boost::optional(我不知道)当然更好!
猜你喜欢
  • 1970-01-01
  • 2017-07-28
  • 2023-03-29
  • 2016-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-21
  • 2013-01-05
相关资源
最近更新 更多