使用不同的关键字搜索数据
Searching data using different keys
我不是C++和STL方面的专家。
我使用Map中的结构作为数据。关键是某个类别C1。我想访问相同的数据,但也使用不同的密钥C2(其中C1和C2是两个不相关的类)。
这在不复制数据的情况下可能吗?我试着在谷歌上搜索,但很难找到一个我能理解的答案。
这适用于不支持boost库的嵌入式目标。
有人能提供帮助吗?
您可以将指向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;
可以使用std::make_shared()
来分配Data
的实例。
不在标准库中,但Boost提供boost::multi_index
两个不同类型的键
我必须承认我看错了一点,并没有真正注意到你想要两个不同类型的键,而不是值。不过,解决方案将基于以下内容。其他答案几乎都是需要的,我只想补充一点,你可以制作一个通用的查找函数:(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]; }
CCD_ 7也是如此。
如果您想将其封装在一个类中,一个明显的选择是将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
的对象,它就会是活动的。
在这种情况下,我通常使用非拥有的指针。我将数据存储在一个向量中:
std::vector<Data> myData;
然后我将指针映射到每个元素。不过,由于指针可能会因为矢量的未来增长而无效,因此在这种情况下,我将选择使用矢量索引。
std::map<Key1, int> myMap1;
std::map<Key2, int> myMap2;
不要向客户端公开数据容器。将元素的插入和移除封装在特定的函数中,这些函数到处插入,到处移除。
Bartek的"创意1"很好(尽管没有令人信服的理由更喜欢unordered_map
而不是map
)。
或者,您可以使用std::map<C2, Data*>
或std::map<C2, std::map<C1, Data>::iterator>
来允许在一次C2
关键字搜索后直接访问Data
对象,但您需要更加小心,不要访问无效(已擦除)的Data
(或者更准确地说,从任何其他用户的角度来看,从两个容器原子地访问erase
)。
一个或两个map
也可以移动到shared_ptr<Data>
,如果这对所有权有帮助的话,另一个可以使用weak_ptr<>
。(这些都在C++11标准中,否则显而易见的源代码boost显然不适合你,但也许你已经实现了自己的库或选择了另一个库?这是现代C++的基本类)。
EDIT-哈希表与平衡二进制树
这与这个问题并不特别相关,但已经收到了下面的评论/兴趣,我需要更多的空间来正确地解决它。一些要点:
1) Bartek随意建议从map
更改为unordered_map
,而不建议影响研究重新迭代器/指针失效,这是危险的,而且没有理由认为这是必要的(这个问题没有提到性能),也没有建议对其进行评测。
3) 程序中相对较少的数据结构对性能关键行为很重要,而且在很多时候,一个与另一个的相对性能无关紧要。支持这一说法——大量代码是用std::map
编写的,以确保在C++11之前的可移植性,并且执行得很好。
4) 当性能是一个严重的问题时,建议应该是"Care=>profile",但要说经验法则是可以的——符合"不要过早地悲观"(例如,请参阅Sutter和Alexandrescu的C++编码标准)——如果这里有人问我,我很乐意默认推荐unordered_map
——但这不是特别可靠。这与推荐我看到的每一个std::map
的用法都有所不同。
5) 这个容器性能方面的跟踪已经开始引入一些有用的见解,但还远远不够全面或平衡。这个问题不是进行这种讨论的合理场所。如果有另一个问题可以解决这个问题,继续讨论是有意义的,并且有人要求我参与,我会在未来一两个月的某个时候这样做。
您可以考虑使用一个普通的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
中的迭代器具有非常好的无效保证。
我也遇到了同样的问题,起初为共享指针持有两个映射听起来很酷。但你仍然需要管理这两张地图(插入、删除等)
然后我想出了其他的方法。我的理由是;访问具有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;
我不确定你的情况是否相同或可调整到这种场景,但它可以是一种选择。
- Visual Studio 2015:Extern "C" 和 "export" 关键字
- C++中的"inline"关键字
- 有根的二进制搜索树.保留与其父级的链接
- 如何确保C++函数在定义之前声明(如override关键字)
- 在C++中搜索嵌套多映射值
- 是否有一种有效的方法来搜索队列中的关键字并覆盖其值
- 在特定字段中关键字搜索后,从文本文件中提取多个记录
- 如何使用tinyxml2(C )将属性用作搜索关键字
- 如何在文件中搜索关键字,然后打印其中包含的字符串
- 使用某些关键字进行搜索以给出所需的输出
- 设计了一个基于两个关键字的搜索系统
- C++,逐行读取并搜索链接到文件中某行的关键字
- 可以同时搜索相同成本的值和关键字的地图?象征主义地图
- 使用不同的关键字搜索数据
- 忽略部分搜索关键字
- 使用多关键字地图进行有效搜索
- 在具有非关键字类型的集合中进行有效搜索
- C++二进制搜索关键字错误
- 最快的方式做关键字搜索在大文本在C/ c++
- 如何找到小于STL集搜索关键字的第一个值