如何根据std::map的值获取它们的前n个键
How can i get the top n keys of std::map based on their values?
如何根据std::map的前n个键的值获取它们?有没有一种方法可以让我得到一个列表,比如说,以最大值为值的前10个键
假设我们有一个类似的地图:
mymap["key1"]= 10;
mymap["key2"]= 3;
mymap["key3"]= 230;
mymap["key4"]= 15;
mymap["key5"]= 1;
mymap["key6"]= 66;
mymap["key7"]= 10;
我只想有一个前10个键的列表,与其他键相比,它的值更大。例如,我们mymap的前4名是
key3
key6
key4
key1
key10
注意:
这些值不是唯一的,实际上它们是每个键的出现次数。我想得到一个最常见的密钥列表
注意2:
如果map不是一个好的候选者,并且你想提出任何建议,请根据c++11来做,我当时不能使用boost。
注3:
如果使用std::unordered_multimap<int,wstring>
,我还有其他选择吗?
map
的顺序基于其键,而不是其值,并且不能重新排序,因此有必要对map
进行迭代,并维护遇到的前十个值的列表,或者如Potatoswatter所评论的,使用partial_sort_copy()
为您提取前N值:
std::vector<std::pair<std::string, int>> top_four(4);
std::partial_sort_copy(mymap.begin(),
mymap.end(),
top_four.begin(),
top_four.end(),
[](std::pair<const std::string, int> const& l,
std::pair<const std::string, int> const& r)
{
return l.second > r.second;
});
请参阅在线演示。
选择不同类型的容器可能更合适,boost::multi_index
值得研究,它是:
允许构建容器,该容器维护具有不同排序和访问语义的一个或多个索引。
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;
int main(int argc, const char * argv[])
{
map<string, int> entries;
// insert some random entries
for(int i = 0; i < 100; ++i)
{
string name(5, 'A' + (char)(rand() % (int)('Z' - 'A') ));
int number = rand() % 100;
entries.insert(pair<string, int>(name, number));
}
// create container for top 10
vector<pair<string, int>> sorted(10);
// sort and copy with reversed compare function using second value of std::pair
partial_sort_copy(entries.begin(), entries.end(),
sorted.begin(), sorted.end(),
[](const pair<string, int> &a, const pair<string, int> &b)
{
return !(a.second < b.second);
});
cout << endl << "all elements" << endl;
for(pair<string, int> p : entries)
{
cout << p.first << " " << p.second << endl;
}
cout << endl << "top 10" << endl;
for(pair<string, int> p : sorted)
{
cout << p.first << " " << p.second << endl;
}
return 0;
}
std::map
不仅不按映射到值进行排序(这些值不需要任何定义的排序顺序),而且不允许重新排列其元素,因此在假设结构上执行++ map[ "key1" ];
将值映射回键将使反向映射无效。
最好的办法是将键值对放入另一个结构中,并在需要反向映射时按值进行排序。如果您一直需要反向映射,则每次更改值时都必须删除、修改和重新添加。
将现有映射排序为新结构的最有效方法是std::partial_sort_copy
,正如Al Bundy(刚才)所示。
由于映射的值没有索引,您必须读取所有内容并选择最大的10个值。
std::vector<mapped_type> v;
v.reserve(mymap.size());
for(const auto& Pair : mymap)
v.push_back( Pair.second );
std::sort(v.begin(), v.end(), std::greater<mapped_type>());
for(std::size_t i = 0, n = std::min<int>(10,v.size()); i < n; ++i)
std::cout << v[i] << ' ';
另一种方法是使用两个映射或一个bimap,这样映射的值就会被排序。
您要查找的算法是nth_element,它对一个范围进行部分排序,使第n个元素位于完全排序范围中的位置。例如,如果你想按降序排列前三项,你可以写(伪C++)
nth_element(begin, begin + 3, end, predicate)
问题是nth_element不适用于std::map。因此,我建议您将数据结构更改为成对的向量(根据您处理的数据量,您可能会发现这是一个更快的数据结构)。所以,在你的例子中,我会这样写:
typedef vector<pair<string, int>> MyVector;
typedef MyVector::value_type ValueType;
MyVector v;
// You should use an initialization list here if your
// compiler supports it (mine doesn't...)
v.emplace_back(ValueType("key1", 10));
v.emplace_back(ValueType("key2", 3));
v.emplace_back(ValueType("key3", 230));
v.emplace_back(ValueType("key4", 15));
v.emplace_back(ValueType("key5", 1));
v.emplace_back(ValueType("key6", 66));
v.emplace_back(ValueType("key7", 10));
nth_element(v.begin(), v.begin() + 3, v.end(),
[](ValueType const& x, ValueType const& y) -> bool
{
// sort descending by value
return y.second < x.second;
});
// print out the top three elements
for (size_t i = 0; i < 3; ++i)
cout << v[i].first << ": " << v[i].second << endl;
#include "stdafx.h"
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <algorithm>
#include <cassert>
#include <iterator>
using namespace std;
class MyMap
{
public:
MyMap(){};
void addValue(string key, int value)
{
_map[key] = value;
_vec.push_back(make_pair(key, value));
sort(_vec.begin(), _vec.end(), Cmp());
}
vector<pair<string, int> > getTop(int n)
{
int len = min((unsigned int)n, _vec.size());
vector<Pair> res;
copy(_vec.begin(), _vec.begin() + len, back_inserter(res));
return res;
}
private:
typedef map<string, int> StrIntMap;
typedef vector<pair<string, int> > PairVector;
typedef pair<string, int> Pair;
StrIntMap _map;
PairVector _vec;
struct Cmp:
public binary_function<const Pair&, const Pair&, bool>
{
bool operator()(const Pair& left, const Pair& right)
{
return right.second < left.second;
}
};
};
int main()
{
MyMap mymap;
mymap.addValue("key1", 10);
mymap.addValue("key2", 3);
mymap.addValue("key3", 230);
mymap.addValue("key4", 15);
mymap.addValue("key6", 66);
mymap.addValue("key7", 10);
auto res = mymap.getTop(3);
for_each(res.begin(), res.end(), [](const pair<string, int> value)
{cout<<value.first<<" "<<value.second<<endl;});
}
最简单的解决方案是使用std::transform
来构建第二张地图:
typedef std::map<int, std::string> SortedByValue;
SortedByValue map2;
std::transform(
mymap.begin(), mymap.end(),
std::inserter( map2, map2.end() ),
[]( std::pair<std::string, int> const& original ) {
return std::pair<int, std::string>( original.second, original.first );
} );
然后提取CCD_ 10的最后n个元素。
或者(可能更高效),您可以使用std::vector<std::pair<int, std::string>>
并排序之后:
std::vector<std::pair<int, std::string>> map2( mymap.size() );
std::transform(
mymap.begin(), mymap.end()
map2.begin(),
[]( std::pair<std::string, int> const& original ) {
return std::pair<int, std::string>( original.second, original.first );
} );
std::sort( map2.begin(), map2.end() );
(请注意,这些解决方案以时间为代价进行优化更多内存。)
- 使用2个键的cpp-stl::优先级队列排序不正确
- C++映射有2个键,这样任何1个键都可以用来获取值
- 无法添加多个键以映射将结构作为键
- C++中同一基础对象的多个键
- c++同一个键的多个键/值对
- 让用户输入一个键,如果找到多个键,则增加值
- C++类似于 std::map 的数据结构,具有多个键级别
- C++使用第二个函数获取字符数组的长度
- QML:多个键按 /发布后未处理一些键
- 使用 k 个键值对为零的存储桶初始化 c++14 unordered_map
- 使用位于 C 字符串中的两个字符*获取子字符串
- 首选数据结构,如果您有两个键并且无法使用Boost
- Cassandra驱动程序用多个键查询
- 在几个键的哈希表处搜索
- SORT(),vector<pair<int,int> >严格基于键值,即使两个键值相同
- Qt同时按下多个键
- 最有可能使用的方法是处理多个键以使用STL容器获取值
- 如何根据std::map的值获取它们的前n个键
- 如何循环multimap以获取每个键的第一个键值对
- 如何使用组合键获取boost::multi_index_container中第一个键的不同计数