- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个带有多个索引的 boost multi_index
容器。如何使用迭代时指定的自定义比较来迭代元素。
例如,假设 Element::name
和 Element::index
由 multi_index
容器索引
bool myCompare(const Element &lhs, const Element &rhs)
{
if(lhs.name == rhs.name)
{
return lhs.index < rhs.index;
}
else
{
return lhs.name < rhs.name;
}
}
但是,迭代不应限于上述情况,而是允许根据类似于 SQL SELECT 排序的 Element 索引成员进行任何排序。
最佳答案
这不是多索引容器的特性。
但是,您可以轻松地创建一个额外的临时索引:
std::vector<boost::reference_wrapper<Element const> > temporary(table.begin(), table.end());
现在您可以根据自定义比较对名为 ordering
的索引进行排序:
std::sort(temporary.begin(), temporary.end(), myCompare);
// iterate table in that order:
for(Element const& e: temporary)
std::cout << e.index << "\t" << e.name << "\n";
Bonus: You easily persist that ordering in a
multi_index::random_accesss
index usingrearrange
:table.get<external>().rearrange(temporary.begin());
(where
external
tags a random access index).
更多注意事项:
您的谓词没有定义适当的弱全序。看来您可能想要这样做:
#include <tuple>
bool myCompare(const Element &lhs, const Element &rhs) {
return std::tie(lhs.name, lhs.index) < std::tie(rhs.name, rhs.index);
}
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/random_access_index.hpp>
struct Element {
int index;
std::string name;
};
#include <tuple>
bool myCompare(const Element &lhs, const Element &rhs) {
return std::tie(lhs.name, lhs.index) < std::tie(rhs.name, rhs.index);
}
namespace bmi = boost::multi_index;
using Table = boost::multi_index_container<Element,
bmi::indexed_by<
bmi::random_access<bmi::tag<struct external> >
> >;
#include <iostream>
#include <vector> // for the temporary index
int main() {
Table table;
// generate 30 random records...
std::generate_n(back_inserter(table), 30,
[]{ return Element { rand()%100, std::string(1, 'a'+rand()%26) }; }
);
{
// temporary index:
std::vector<boost::reference_wrapper<Element const> > temporary(table.begin(), table.end());
// iterate table in the order specified by myCompare:
std::sort(temporary.begin(), temporary.end(), myCompare);
for(Element const& e: temporary)
std::cout << e.index << "\t" << e.name << "\n";
// now to rearrange a random-access index on the multi-index container:
table.get<external>().rearrange(temporary.begin());
}
}
打印(例如)
98 a
21 b
93 b
15 c
56 d
62 d
62 d
67 d
91 e
84 f
62 g
49 h
11 i
40 k
29 l
29 m
63 o
86 q
67 r
69 r
77 r
90 r
82 s
93 s
22 w
83 w
96 x
11 y
13 y
72 y
您可以看到,在名称相同的地方,索引较低的在前。
更新评论:
Hmm? Are you asking for magic fairy dust?
你是要魔法仙尘吗?没有魔法。
DBMS 不使用任何异常的东西。他们通常使用 BTree,与您花园下面的数据结构非常相似各种 std::map
,或者实际上是 bmi::ordered_[non_]unique
索引。所以在这方面 Boost MultiIndex 是(接近)你想要的,已经。
RDBMS-es 给表带来的主要补充是持久性。有了它,一切都变得更有用、更具可扩展性并且……更少高效的。
So, don't look at DBMS-es for the holy grail of efficiency.
内存中的键值数据存储被广泛用于 boost 性能是有原因的。另一个重要的注意事项是检索一个SQL 中的有序结果集根本无法正常执行,除非索引已经存在。
现在,如果你想要最好的性能,你可能想要设计你自己的数据结构(也许在 Boost 的帮助下侵入性),但看到你提出这些问题的水平,我会在之前长时间使用 Boost Multi Index你做。只需创建您有时可能需要组合的索引,并编写一些“循环代码”¹,根据需要组合它们。
现在跳出框框思考,您可能想知道如何以 DBMS 的方式“轻松”实现两级排序引擎可能。
与 DBMS 引擎一样,最简单的事情就是准备好一个始终保持最新的索引:<强> Demo
using Table = boost::multi_index_container<Element,
bmi::indexed_by<
bmi::sequenced<bmi::tag<struct insertion_order> >,
// ready made index for traversal in composite order
bmi::ordered_non_unique<bmi::tag<struct readymade>,
bmi::composite_key<Element,
bmi::member<Element, std::string, &Element::name>,
bmi::member<Element, int, &Element::index>
>
>
> >;
int main() {
// generate 30 random records...
Table table;
std::generate_n(back_inserter(table), 30, []{ return Element { rand()%100, std::string(1, 'a'+rand()%26) }; });
// effectively "zero" cost iteration there:
for(Element const& e: table.get<readymade>())
std::cout << e.index << "\t" << e.name << "\n";
}
请注意,您也可以部分地在 Boost MultiIndex 中使用有序复合索引:
for(Element const& e: boost::make_iterator_range(table.get<readymade>().equal_range("y")))
std::cout << e.index << "\t" << e.name << "\n";
打印(对于与上面相同的随机种子):
11 y
13 y
72 y
或者,您可以定义单独的索引,并将它们与您自己的算法一起使用以实现二级排序:
using Table = boost::multi_index_container<Element,
bmi::indexed_by<
bmi::sequenced<bmi::tag<struct insertion_order> >,
// separate indices that we might combine in some way later::
bmi::ordered_non_unique<bmi::tag<struct by_index>, bmi::member<Element, int, &Element::index> >,
bmi::ordered_non_unique<bmi::tag<struct by_name>, bmi::member<Element, std::string, &Element::name> >
> >;
现在合并索引成为“引擎”的工作,在本例中是您的算法。这是一个想法:
template <typename Index1, typename Index2, typename Table, typename Function>
void SelectOrderBy2(Table const& table, Function function) {
using T = typename Table::value_type const;
auto& idx1 = table.template get<Index1>();
auto& idx2 = table.template get<Index2>();
auto it = idx1.begin(), end = idx1.end();
while (it!=end) {
auto next = idx1.upper_bound(idx1.key_extractor()(*it));
std::set<boost::reference_wrapper<T>, typename Table::template index<Index2>::type::value_compare>
set(idx2.value_comp());
while (it != next)
set.insert(set.end(), boost::cref(*it++));
for (auto& e: set)
function(e);
}
}
这是一些非常容易出错的模板代码,但您可以非常简单地使用它:
SelectOrderBy2<by_name, by_index>(
table,
[](Element const& e) { std::cout << e.index << "\t" << e.name << "\n"; }
);
Live On Coliru 也可以看到
¹ 或许更适合称为通用/专用算法……:)
关于c++ - 使用自定义顺序遍历 boost multi_index,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32428494/
这是我的 multi_index 代码: struct tag_type {}; typedef boost::multi_index_container, b
class ObjectStorage { private: std::string objName; int zIndex; // Refer
2个问题: 1. 我真的需要通过成员将参数传递给 modify/modify_key 吗? 2. 为什么会出现这个编译错误 要查看包含错误的完整代码,您可以查看http://coliru.stacke
我有一个包含多个 hashed_unique 索引(A、B、C)的 multi_index。 并非所有对哈希的插入都包含所有索引的信息。一些索引可能是空的。有些可能包含所有条目。 我将它们定义为 ha
为了避免 msvc2010 编译器错误,我在 composite_key 中使用用户定义的 key 提取器,如下所示: enum NodeType { TypeOne = 0, T
首先我想展示工作代码,然后解释我想如何改变。这是简单的 boost multi_index 示例: //main.cpp #include #include #inc
我有一个带有多个索引的 boost multi_index 容器。如何使用迭代时指定的自定义比较来迭代元素。 例如,假设 Element::name 和 Element::index 由 multi_
所以。我正在使用 igraph 对象,我想以特定顺序迭代顶点。顺序由称为“值”的顶点属性确定,我想按从高到低的顺序进行操作。 igraph 可以按顶点 ID 顺序将所有值作为 igraph_vecto
我想按顺序搜索 boost::multi_index 容器并按顺序获取下一个元素。 下面的代码存储了四个具有不同索引(顺序和有序)的 float 。 最后一个 if 语句是问题所在。我不知道如何编辑以
我的应用程序中有一个 boost::multi_index 容器,它包含对象的共享指针 (std::shared_ptr)。正如我从文档中了解到的那样,它创建了具有对唯一索引的双向访问的树结构。是否可
阅读 boost::multi_index 引用文献,我发现 iterator_to 方法具有恒定顺序。这怎么可能?我的意思是,如果迭代器是一个不同于它所代表的 value_type 的对象,容器怎么
其定义如下: typedef boost::multi_index_container, boost::multi_index::member, boost::mult
我正在尝试制作一个 boost::multi_index 容器,它使用带参数的成员函数作为键。 class Data { public: std::string get(const std::s
我有一个 boost::multi_index 容器。谁能告诉我如何根据某个键检索一系列迭代器?经过几个小时的搜索,我想到 lower_bound 或 upper_bound 应该可以解决问题,但我仍
这个问题在这里已经有了答案: Where and why do I have to put the "template" and "typename" keywords? (8 个答案) 关闭 5
我正在应用 boost multi_index 示例的示例 6。 https://www.boost.org/doc/libs/1_71_0/libs/multi_index/doc/examples
我有以下(简化的)代码: #include #include namespace bmi = boost::multi_index; #include #include #include u
我想在内部实现 boost 多索引两组具有相同搜索条件但不同驱逐条件的键。假设我有两组具有相同搜索条件的数据,但一组需要 100 的 MRU(最近使用)列表,另一组需要 200 的 MRU。假设条目是
我有这个结构: struct myData { unsigned long id; int age; int phone; myData(){}; myDa
假设我有一个对象,可以通过来自不同 namespace 的不同名称来标识: enum Namespace { nspaceA, nspaceB }; struct Object {
我是一名优秀的程序员,十分优秀!