使用不同的键搜索数据

时间:2013-07-16 10:07:37

标签: c++ stl

我不是C ++和STL的专家。

我在Map中使用结构作为数据。关键是一些C1级。 我想访问相同的数据,但也使用不同的键C2(其中C1和C2是两个不相关的类)。

这是否可以在不重复数据的情况下实现? 我尝试在谷歌搜索,但很难找到一个我能理解的答案。

这适用于不支持boost库的嵌入式目标。

有人可以提供帮助吗?

7 个答案:

答案 0 :(得分:4)

您可以将指针存储为Data作为std::map值,并且您可以使用两个不同键的地图指向相同的数据。

我认为 std::shared_ptr 之类的智能指针在这种共享数据所有权的情况下是一个不错的选择:

#include <map>       // for std::map
#include <memory>    // for std::shared_ptr

....

std::map<C1, std::shared_ptr<Data>> map1;
std::map<C2, std::shared_ptr<Data>> map2;

可以使用Data分配std::make_shared()的实例。

答案 1 :(得分:3)

不在标准库中,但Boost提供boost::multi_index

答案 2 :(得分:3)

两种不同类型的键

我必须承认我有点误读,并没有真正注意到你想要2个不同类型的键,而不是值。然而,解决方案将基于以下内容。其他答案几乎都需要它,我只想补充一点,你可以创建一个通用查找函数:(C ++ 14-ish伪代码)。

template<class Key> 
auto lookup (Key const& key) { }

专注于你的钥匙(可以说比SFINAE更容易)

template<>
auto lookup<KeyA> (KeyA const& key) { return map_of_keys_a[key]; }

同样适用于KeyB

如果您想将其封装在一个类中,一个明显的选择是将lookup更改为operator[]


相同类型的键,但值不同

创意1

我能在60秒内想到的最简单的解决方案:(最简单的意思是它应该经过深思熟虑)。我也会默认切换到unordered_map

map<Key, Data> data;
map<Key2, Key> keys;

通过data[keys["multikey"]]访问。

这显然会浪费一些空间(复制Key类型的对象),但我假设它们比Data类型小得多。

创意2

另一个解决方案是使用指针;然后重复的唯一成本是(智能)指针:

map<Key, shared_ptr<Data>> data;

只要至少有一个键指向它,Data的对象就会存活。

答案 3 :(得分:2)

在这些情况下我通常使用的是非拥有指针。我将数据存储在一个向量中:

std::vector<Data> myData;

然后我将指针映射到每个元素。但是,由于向量的未来增长,指针可能无效,但在这种情况下,我将选择使用向量索引。

std::map<Key1, int> myMap1;
std::map<Key2, int> myMap2;

不要将数据容器暴露给您的客户端。在特定函数中封装元素插入和删除,这些函数随处插入并随处删除。

答案 4 :(得分:1)

Bartek的“想法1”很好(尽管没有令人信服的理由偏好unordered_mapmap)。

或者,您可以拥有std::map<C2, Data*>std::map<C2, std::map<C1, Data>::iterator>,以便在一次Data - 键控搜索后直接访问C2个对象,但之后您需要更小心的是不要从任何其他用户的角度原子地从两个容器中访问无效(已擦除)Data(或者更确切地说,从erase访问。)

一个或两个map也可以移至shared_ptr<Data> - 另一个可以使用weak_ptr<>,如果这有助于所有权。 (这些都在C ++ 11标准中,否则明显的来源 - 提升 - 显然是出于你的想法,但也许你已经实现了自己的或者选择了另一个库?现代C ++的基础类。)

编辑 - 哈希表与平衡二叉树

这与问题并不特别相关,但在下面收到了意见/兴趣,我需要更多空间来妥善解决问题。一些要点:

1)Bartek随便建议从map更改为unordered_map而不建议影响研究重新迭代器/指针失效是危险,并且没有理由认为没有理由它是需要的(问题没有提及表现),也没有建议.- / p>

3)程序中相对较少的数据结构对性能关键行为很重要,并且很多时候,一个与另一个的相对性能无关紧要。支持这种说法 - 大量代码是用std::map编写的,以确保在C ++ 11之前的可移植性,并且表现得很好。

4)当表现是一个严重的问题时,建议应该是“Care =&gt; profile”,但是说经验法则是正确的 - 符合“不要过早悲观”(参见例如Sutter和Alexandrescu的C ++编码标准) - 如果在这里被要求提供一个,我很乐意默认推荐unordered_map - 但这并不是特别可靠。这是一个世界,而不是推荐每个std::map用法我认为会被改变。

5)这个容器性能方面已经开始引入有用洞察力的临时片段,但远非全面或平衡。这个问题对于这样的讨论并不是一个理智的场所。如果有另一个问题解决这个问题,那么继续这个讨论是有意义的,有人要求我参与进来,我会在接下来的一两个月内完成。

答案 5 :(得分:1)

您可以考虑使用普通std::list保存所有数据,然后将各种std::map对象映射到指向列表的迭代器:

std::list<Data> values;
std::map<C1, std::list<Data>::iterator> byC1;
std::map<C2, std::list<Data>::iterator> byC2;

即。而不是摆弄或多或少的原始指针,你使用普通的迭代器。并且std::list中的迭代器具有非常好的失效保证。

答案 6 :(得分:0)

我遇到了同样的问题,首先拿着两张地图共享指针听起来很酷。但是你仍然需要管理这两个地图(插入,删除等......)。

我想出了其他方法。 我的理由是;访问具有x-y或半径角的数据。想想每个点都会保存数据,但点可以描述为笛卡尔x,y或半径角。

所以我写了一个类似

的结构
struct MyPoint
{
    std::pair<int, int> cartesianPoint;
    std::pair<int, int> radianPoint;

    bool operator== (const MyPoint& rhs)
    {
         if (cartesianPoint == rhs.cartesianPoint || radianPoint == rhs.radianPoint)
             return true;
         return false;
    }
}

之后我可以将其用作关键,

std::unordered_map<MyPoint, DataType> myMultIndexMap;  

我不确定你的情况是否相同或可调整到这个场景,但它可以是一个选项。