地图的联合迭代器?
[前言:像 std::map
这样的关联 C++ 容器有点像只有一个键列的微型数据库。 Boost 的 bimap
将其提升为两列表,在两列中都进行查找,但这只是类比 - 没有“polymap”概括这个想法。]
无论如何,我我想继续将地图视为数据库,现在我想知道是否有一个迭代器(或其他解决方案)允许我对多个组成地图进行联合。也就是说,所有映射都具有相同的类型(或至少是值类型和比较器),并且我想要一个迭代器,它将整个集合视为一个大的多重映射(重复的键是可以的),并让我以正确的联合方式遍历它命令。
Boost 中是否存在这样的东西?还是说很容易装起来?在伪代码中:
std::map<K, M> m1, m2;
union_iterator<K, M> u(m1, m2)
for(auto it = u.begin(); it != u.end(); ++it) { /* ... */ }
例如,如果我们有:
m1 = { { 9:00, "Check in"}, { 12:00, "Break" }, { 16:00, "Check out"} };
m2 = { { 10:30, "coffee" }, { 12:15, "baked beans" }, { 15:00, "lies" } };
那么我希望迭代器生成:
9:00, "Check in"; 10:30, "coffee"; 12:00, "Break"; 12:15, "baked beans"; ...
[Preface: The associative C++ containers like std::map
are a bit like micro-databases with just one key column. Boost's bimap
elevates this to a two-column table with lookup in both columns, but that that's as far as the analogy goes -- there's no "polymap" that generalizes the idea.]
In any event, I want to keep thinking of maps as databases, and I now wonder if there is an iterator (or some other solution) that allows me to do a UNION of several constituent maps. That is, all maps have the same type (or value type and comparator, at least), and I want a single iterator that treats the entire collection as a big multimap (repeated keys are OK) and lets me traverse it in the correct unioned order.
Does such a thing exist, perhaps within Boost? Or is it easy to rig one up? In pseudo code:
std::map<K, M> m1, m2;
union_iterator<K, M> u(m1, m2)
for(auto it = u.begin(); it != u.end(); ++it) { /* ... */ }
For example, if we had:
m1 = { { 9:00, "Check in"}, { 12:00, "Break" }, { 16:00, "Check out"} };
m2 = { { 10:30, "coffee" }, { 12:15, "baked beans" }, { 15:00, "lies" } };
then I want the iterator to produce:
9:00, "Check in"; 10:30, "coffee"; 12:00, "Break"; 12:15, "baked beans"; ...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
有一个“polymap”: Boost.MultiIndex。
There is a "polymap": Boost.MultiIndex.
正如我宣布的,我得到了一些非常酷的东西。
我现在发布它,因为我不确定今晚是否能及时回来发布它。我将花几句话来解释一下。 (在这篇文章中)
关于这段代码可以说很多:它不是很高效,而且还不是很干净。然而,它几乎是无限通用的,并且应该像其他任何东西一样扩展。所有代码都可以在 github gist 中找到:
(我并不是说用整数和浮点数键控地图是一个好主意(更不用说同时两者) - 只是表明它可以完成)
这是 test.cpp 的输出,您可以找到它:
As I announced, I have got something pretty cool.
I'm posting it now, because I wouldn't be sure whether I'd be back in time tonight to post it. I will be spending a few words in explanation. (in this post)
A lot can be said about this code: it is not very efficient, and not very clean (yet). It is, however, nearly infinitely generic and should scale like anything else. All code can be found in a github gist:
(I'm not saying that it would be a good idea to have maps keyed with ints and floats (let alone both at the same time) - just showing that it can be done)
Here is the output of the test.cpp as you can find it:
将两个
mapS
复制到临时文件中,将一个附加到另一个文件中(如果您可以修改它们),或者使用vector
作为std::set_union 的临时文件
和自定义比较器是最简单的替代解决方案。Either copying both
mapS
into a temporary, appending one to the other (in case you can modify them) or using avector
as a temporary withstd::set_union
and a custom comparator are the easiest alternative solutions.以下是我如何实现 thiton 的答案:
它的用法与
union_iterator
略有不同,但它实现了基本思想。您可以扩展构造函数以接受多个适合的映射,并在while (iterator.next())
循环中使用它,而不是for (...)
环形。编辑:我通过同时执行所有弹出和推送来简化
next()
。所以现在就更简单了! (也可以花费一些精力使其像 STL 迭代器,但这会变得乏味。)Here's how I would implement thiton's answer:
It has slightly different usage than
union_iterator<K, V>
but it implements the basic idea. You can expand the constructor to accept multiple maps however you fit, and use it in awhile (iterator.next())
loop instead of afor (...)
loop.EDIT: I simplified
next()
by doing all the popping and pushing at once. So now it's even simpler! (One could also expend some effort making it like a STL iterator, but that gets tedious.)使用 boost function_output_iterator 的非常简单的解决方案:
我们可以通过使用 boost::set_union (范围版本)而不是 std::set_union 使这个解决方案更漂亮。
UPD 更新版本使用不同的键/值类型:
UPD2 std::set_union 替换为 std::merge
Very simple solution using boost function_output_iterator:
We can make this solution prettier by using boost::set_union (range version) instead of std::set_union.
UPD Updated version use different key/values types:
UPD2 std::set_union replaced with std::merge
装配应该相当容易:对于 N 个基本映射,您的迭代器包含一个优先级队列,该优先级队列由基本迭代器指向的元素的 N 个键确定优先级。对于取消引用,请取消引用队列前端的迭代器。对于增量,在队列前端增加迭代器,如果增量不在队列末尾,则重新插入它。
Rigging up should be fairly easy: For N base maps, your iterator contains a priority queue prioritized by the N keys of the elements the base iterators point to. For dereference, dereference the iterator at the queue front. For increment, increment the iterator at the queue front and, if it's increment is not at the end, re-insert it.
下面是如何很容易地完成它:
但真正的问题是实现普通迭代器所需的所有剩余成员函数:-)。 Boost 有一些库可以帮助你做到这一点,但它可能仍然相当困难。
Here's how it can be done quite easily:
But the real problem is implementing all the remaining member functions required by normal iterators :-). Boost has some lib for helping you do it, but it might still be quite difficult.
这不是您要求的迭代器,但我刚刚在标准库中找到了这个函数:
还有
std::set_intersection
、std::set_difference
和std::set_symmetry_difference
This isn't an iterator like you asked for, but I just found this function in the standard library:
There's also a
std::set_intersection
,std::set_difference
, andstd::set_symmetric_difference