C++ 多索引映射

Posted

技术标签:

【中文标题】C++ 多索引映射【英文标题】:C++ a multiple indexes map 【发布时间】:2021-07-12 01:47:23 【问题描述】:

我正在实现一个简单的搜索系统,其中所有数据都存储在正在运行的进程的内存中。

最初,我打算使用元组的映射来实现这一点。

map<tuple<int, string, ...>, string> dict

但是,它只有在所有密钥都已知且不丢失时才有效。

例如,比如说,我有, map, value> 字典;

如果没有 key2 或 key2 是“无关”,我无法搜索地图

C++ 中是否有任何标准库或函数可以做到这一点?

非常感谢任何帮助。

【问题讨论】:

不,C++ 库中没有这样的东西。由于许多基本原因,在技术上不可能做任何事情,无论是使用地图还是 C++ 库中的任何其他关联容器。您将必须设计和实现自己的容器,该容器为每个键使用单独的映射/无序映射。 诚实的问题,但是您是否考虑过使用关系数据库?这将使进行任意查询变得更加容易,并且它们旨在为您处理索引和存储。 不,由于要求,它不打算使用数据库。 【参考方案1】:
std::map<int, std::map<string, std::map< ... , string > ... > > dict;

您可以在任何步骤“不在乎”。您必须检查那里的每一个可能性。

你可以做一个组合爆炸来做所有 n!排序,并让所有内容都指向一个共享指针或类似的东西。

这并不便宜。

在每种可能性(n!)中排列参数,然后从每个增强选项(具有最小和最大状态)的元组映射到相同的共享数据 ptr。您现在可以执行将左侧或右侧视为最不重要的排序,并使用equal_range 不关心该键。

您可以改为使用四叉树或八叉树或 n 树结构之类的东西进行攻击。这会进行多维“排序”。让它与任意键一起工作会很有趣。

【讨论】:

而不是在每种可能性中排列参数,也许可以考虑使用类似 map>>, map>>, map>> 等等。那么,假设我只指定了key1和key3(没有key2),我可以搜索key1和key3映射,然后比较vector>取交集【参考方案2】:

这是我几年前碰巧研究过的一个有趣且重要的问题:

问题在于,在给定 n 个键的情况下,能够有效地查询这些键的任意子集。 在数据库术语中,这可以通过创建 m 索引来解决,这样每​​个键组合都被某个索引覆盖。问题描述here:索引数为C(n,floor(n/2)),其中 C(a,b) 是二项式系数a choose b。对于 n=5,所需索引的数量为 m=10。 我设计了an algorithm 来确定实际索引是什么。在 n=5 且键为 abcd的情况下>, e, 你可以使用索引(acedb),(baedc),(bdaec),(bedca),(cbaed),(cdbae),(cebad),(daceb), (decab),(eadbc)。这里的一个关键方面是索引可以用于较短的键组合。例如,(acedb) 涵盖以下内容(按字母顺序重新排列):(a),(ac),(ace),(acde),(abcde)。这就是为什么您可以仅使用 10 个索引而不是 25-1=31 来覆盖任意组合的原因。 现在,Boost.MultiIndex 可用于实际指定和使用这些索引。 example 有 4 个键,如果您愿意,可以轻松扩展到 5 个键。

【讨论】:

【参考方案3】:

你问:

C++ 中是否有任何标准库或函数可以做到这一点?

这个问题的答案是

要求有点模糊,因为您似乎有一个特定的界面。你应该定义你的接口,以及你期望它们做什么。

find()like 函数的实现可以用多索引数据结构来实现。大致:

为所有记录创建一个容器(如set)。 对于每个关键字段,创建一个map,将该关键字段中的值与set 记录中的迭代器set 相关联。 find 方法将遍历键 maps 的集合,并计算返回的迭代器 sets 的交集。

【讨论】:

这似乎与我在上一个解决方案中刚刚回答的想法相似。也就是为每个关键字段创建一个映射【参考方案4】:

不在std 中,但有boost::multi_index,它允许您将数据的任意投影指定为键,并且您可以拥有任意数量的键。

// your keys and value
struct Datum 
    key1_t key1;
    key2_t key2;
    key3_t key3;
    // etc ...
    value_t value;
;

namespace bmi = boost::multi_index;

// some unique types
struct Key1 ;
struct Key2 ;
struct Key3 ;
struct Key1Key2 ;
struct Key1Key2Key3 ;

using Dict = boost::multi_index_container<Datum, bmi::indexed_by<
    bmi::ordered_unique<bmi::tag<Key1>, bmi::key<&Datum::key1>>, // just key 1
    bmi::ordered_unique<bmi::tag<Key2>, bmi::key<&Datum::key2>>, // just key 2
    bmi::ordered_unique<bmi::tag<Key3>, bmi::key<&Datum::key3>>, // just key 3
    bmi::ordered_unique<bmi::tag<Key1Key2>, bmi::key<&Datum::key1, &Datum::key2>>, // key 1 then key 2
    bmi::ordered_unique<bmi::tag<Key1Key2Key3>, bmi::key<&Datum::key1, &Datum::key2, &Datum::key3>>, // key 1 then key 2 then key 3
>;
int main() 
    Dict dict = /* stuff */

    key1_t key1 = /* stuff */
    key2_t key2 = /* stuff */
    key3_t key3 = /* stuff */

    auto it1 = dict.get<0>().find(key1); // select which by position
    auto it2 = dict.get<Key2>().find(key2); // or by the tag types 
    auto it5 = dict.get<Key1Key2Key3>().find( key1, key2, key3 ); // multiple keys

【讨论】:

看起来不错,但是从您的代码看来,我需要指定所有的键组合?我的意思是,如果我有 10 个(甚至更多)键,那就太多了。

以上是关于C++ 多索引映射的主要内容,如果未能解决你的问题,请参考以下文章

Pandas 将列多索引转换为行多索引

重映射引脚

多索引表 (10)iterator迭代器多索引

按列名和多索引向多索引数据框添加值

STM32端口复用和重映射

熊猫将第一个多索引转换为行索引,将第二个多索引转换为列索引