我在unordered_multimap中插入了一些元素,我发现使用相等范围映射到键k的所有值。现在我想通过它们的插入顺序遍历这些映射值。查看代码以便更好地理解。
#include <iostream>
#include <unordered_map>
using namespace std;
int main()
{
unordered_multimap<int,int> m;
m.insert(make_pair(1,2));
m.insert(make_pair(1,3));
m.insert(make_pair(1,4));
auto it = m.equal_range(1);
for(auto it1 = it.first; it1 != it.second; it1++) {
cout<<it1->second<<endl;
}
}
输出:
4
3
2
但我想按照插入键和映射值的顺序进行遍历。所以,我想按2,3,4顺序遍历。有可能吗?
答案 0 :(得分:2)
没有一种直截了当的方式去做你想要的事情。当元素插入有序或无序多图中时,它们实际上被放置在内部结构中,并且不知道它们的放置顺序。
你应该有辅助,例如一个std::queue
容器,用于将迭代器附加到inserted元素。迭代器可以从插入中获得:
auto inserted_pos = m.insert(make_pair(1,4));
请记住,插入过程中迭代器不会失效。如果删除元素,它们将失效,并且仅对相关元素无效。
答案 1 :(得分:0)
这是达到你想要的一种方式。
它使用boost::multi_index
提供的一些技巧。
注意使用project
将一个索引中的迭代器转换为另一个索引中的迭代器。
#include <iostream>
#include <vector>
#include <algorithm>
#include <utility>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/member.hpp>
namespace example {
struct by_id {};
struct by_insertion_order {};
using namespace boost;
using namespace boost::multi_index;
using item_type = std::pair<int, int>;
typedef multi_index_container<
item_type, // what we are storing
indexed_by<
// unordered multimap-type index
hashed_non_unique<tag<by_id>, member<item_type, int, &item_type::first> >,
// sequence-type index - records insertion order
sequenced<tag<by_insertion_order>>
>
> my_store;
using const_insertion_sequence_iterator = decltype(std::declval<my_store>().get<by_insertion_order>().cbegin());
using const_by_id_iterator = decltype(std::declval<my_store>().get<by_id>().cbegin());
// convert a range of 'by_id' iterators to an ordered vector 'by_insertion_sequence' iterators
// @param store is a reference to the store for which the iterators are valid
// @param first is the first by_id iterator in the filtered range
// @param last is the 'one past the end' iterator of the filtered range
// @returns a vector of iterators to items ordered by insertion sequence
auto
projected_to_insertion_order(const my_store& store,
const_by_id_iterator first,
const_by_id_iterator last)
-> std::vector<const_insertion_sequence_iterator>
{
std::vector<const_insertion_sequence_iterator> result;
for ( ; first != last ; ++first) {
result.push_back(store.project<by_insertion_order>(first));
}
sort(result.begin(),
result.end(),
[&store](const auto& il, const auto& ir) {
return distance(store.get<by_insertion_order>().cbegin(), il)
< distance(store.get<by_insertion_order>().cbegin(), ir);
});
return result;
}
}
int main()
{
using namespace std;
using example::my_store;
using example::by_id;
using example::by_insertion_order;
using example::projected_to_insertion_order;
// define store
my_store m;
// add some items
m.get<by_id>().emplace(1,2);
m.get<by_id>().emplace(3,6);
m.get<by_id>().emplace(1,3);
m.get<by_id>().emplace(2,5);
m.get<by_id>().emplace(1,4);
// get range of items filtered by id
auto ip = m.get<by_id>().equal_range(1);
cout << "filtered but unordered\n";
for (auto it = ip.first ; it != ip.second ; ++it) {
cout << it->first << ":" << it->second << endl;
}
// project that to a vector of iterators to items ordered by insertion sequence
cout << "filtered and ordered by insertion sequence\n";
for (const auto& it : projected_to_insertion_order(m, ip.first, ip.second)) {
cout << it->first << ":" << it->second << endl;
}
}
预期产出:
filtered but unordered
1:4
1:3
1:2
filtered and ordered by insertion sequence
1:2
1:3
1:4