Boost multi_index:检索非唯一键的唯一值

发布于 2024-10-17 19:24:15 字数 452 浏览 0 评论 0原文

我有一个 boost::multi_index_container ,其元素是这样的结构:

struct Elem {
    A a;
    B b;
    C c;
};

主键(在数据库意义上)是 acomposite_keyb。其他 键的存在是为了执行各种类型的查询。

我现在需要检索 c 的一组所有不同值。这些值是 无论如何不是唯一的,但是迭代所有条目(尽管是有序的), 或使用 std::unique 似乎相当浪费,考虑到 c 的不同值的数量预计为 <<比总数 条目数(例如 10 到 1000)。

我是否缺少一种更有效地获得此结果的简单方法?

I have a boost::multi_index_container whose elements are structs like this:

struct Elem {
    A a;
    B b;
    C c;
};

The main key (in a database sense) is a composite_key of a and b. Other
keys exist to perform various types of queries.

I now need to retrieve a set of all different values of c. These values are
by all means not unique, but iterating through all entries (albeit ordered),
or using std::unique seems quite a waste, considering that
the number of different values of c is expected to be << than the total
number of entries (say, 10 to 1000).

Am I missing a simple way to obtain this result more efficiently?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

任谁 2024-10-24 19:24:15

我搜索了 Boost.MultiIndex 文档,似乎找不到一种方法来完成您想要的操作。我有兴趣知道这是否可行。

也许您能做的最好的事情就是在您的 multi_index_container 旁边维护一个 std::map (或哈希映射),并使它们保持“同步”。

该映射将 C 值与其出现次数(频率)相关联。它本质上是 C 值的直方图。每次将 Elem 添加到 multi_index_container 时,都会增加直方图中相应的频率。当您从 multi_index_counter 中删除 Elem 时,直方图中相应的频率就会减少。当频率达到零时,您可以从直方图中删除该条目。

要检索一组不同的 C 值,您只需迭代直方图中的 对并查看每对的 key 部分即可。如果您使用了 std::map,那么不同的 C 值将会排序。

如果您只想检查一组不同的 C 值一次(或很少),那么我上面描述的方法可能有点矫枉过正。一种更简单的方法是将所有 C 值插入到 std::set中,然后迭代该集合以检索不同的 C 值。

你说不同的 C 的集合比 C 的总数小得多。因此,std::set 方法比将 C 复制到 std::vector、对向量进行排序,然后运行 ​​std 浪费的空间要少得多::独特

让我们比较一下复制到集合与复制到向量、排序然后运行 ​​unique 的时间复杂度。令 N 为 C 值的总数,令 M 为不同 C 值的数量。根据我的计算,集合方法的时间复杂度应该为 O(N*log(M))。由于 M 很小并且不会随着 N 的增加而增长太多,因此复杂度实际上变成了 O(N)。另一方面,排序+独特技术的时间复杂度应该为 O(N*log(N))。

I scoured the Boost.MultiIndex documentation and can't seem to find a way to do what you want. I'm interested in knowing if it's doable.

Perhaps the best you can do is maintain a std::map<C, size_t> (or hash map) alongside your multi_index_container and keep them both "synchronized".

The map associates a C value with its occurrence count (frequency). It's essentially a histogram of C values. Each time you add an Elem to your multi_index_container, you increment the corresponding frequency in the histogram. When you remove an Elem from your multi_index_counter, you decrement the corresponding frequency in the histogram. When the frequency reaches zero, you delete that entry from the histogram.

To retrieve the set of distinct C values, you simply iterate through the <key,value> pairs in the histogram and look at the key part of each pair. If you used a std::map, then the distinct C values will come out sorted.

If you're going to examine the set of distinct C values only once (or rarely) then the approach I described above may be overkill. A simpler approach would be to insert all C values into a std::set<C> and then iterate through the set to retrieve the distinct C values.

You said that the set of distinct C's is much smaller then the total number of C's. The std::set<C> approach should therefore waste much less space than copying the C's to a std::vector, sorting the vector, then running std::unique.

Let's compare the time complexity of copying to a set versus copying to a vector, sorting, then running unique. Let N be the total number of C values, and let M be the number of distinct C values. The set approach, by my reckoning, should have a time complexity of O(N*log(M)). Since M is small and does not grow much with higher N's, the complexity effectively becomes O(N). The sorting+unique technique, on the other hand, should have a time complexity of O(N*log(N)).

滴情不沾 2024-10-24 19:24:15

我解决这个问题的方法是使用升压范围适配器,如下所示

const auto& indexedContainer = container.get<IndexType>();
const auto uniqueIndexRange = indexedContainer 
    | boost::adaptors::transformed([&](auto&& v) {
        return indexedContainer.key_extractor()(v); })
    | boost::adaptors::uniqued;

The approach I took to solving this problem was to use boost range adaptors as follows

const auto& indexedContainer = container.get<IndexType>();
const auto uniqueIndexRange = indexedContainer 
    | boost::adaptors::transformed([&](auto&& v) {
        return indexedContainer.key_extractor()(v); })
    | boost::adaptors::uniqued;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文