[英]How can I sort an STL map by value?
如何实现 STL map 按值排序?
例如,我有一个 map m
:
map<int, int> m;
m[1] = 10;
m[2] = 5;
m[4] = 6;
m[6] = 1;
我想按m
的值对 map 进行排序。 所以,如果我打印 map,我想得到如下结果:
m[6] = 1
m[2] = 5
m[4] = 6
m[1] = 10
如何以这种方式对 map 进行排序? 有什么方法可以用排序值处理键和值?
首先将所有键值对转储到set<pair<K, V> >
,其中使用小于函子构造该set
,该函子仅比较该对的第二个值。 这样,即使您的值不完全不同,您的代码仍然有效。
或者将键值对转储到vector<pair<K, V> >
,然后使用相同的小于函子对该向量进行排序。
您可以构建第二个映射,将第一个映射的值作为键,将第一个映射的键作为值。
这仅在所有值都不同时才有效。 如果您不能假设这一点,那么您需要构建一个多地图而不是地图。
我想知道如何按值实现 STL 映射排序。
你不能,根据定义。 映射是一种按键对其元素进行排序的数据结构。
您应该将Boost.Bimap用于此类事情。
基于@swegi 的想法,我在c++11 中使用multimap
实现了一个解决方案:
map<int, int> m = {{1, 10}, {2, 5}, {4, 6}, {6, 1}};
multimap<int, int> mm;
for(auto const &kv : m)
mm.insert(make_pair(kv.second, kv.first)); // Flip the pairs.
for(auto const &kv : mm)
cout << "m[" << kv.second << "] = " << kv.first << endl; // Flip the pairs again.
我还使用成对的向量实现了基于@Chris 的想法的 C++11 解决方案。 为了正确排序,我提供了一个lambda 表达式作为比较函子:
map<int, int> m = {{1, 10}, {2, 5}, {4, 6}, {6, 1}};
using mypair = pair<int, int>;
vector<mypair> v(begin(m), end(m));
sort(begin(v), end(v), [](const mypair& a, const mypair& b) { return a.second < b.second; });
for(auto const &p : v)
cout << "m[" << p.first << "] = " << p.second << endl;
第一种解决方案更紧凑,但两种解决方案应该具有大致相同的性能。 插入multimap
是O(log n) ,但这必须对n个条目完成,导致O(n log n) 。 对第二个解决方案中的向量进行排序也会导致O(n log n) 。
我还尝试了@Chris 关于使用一组对的想法。 但是,如果这些值不是完全不同的,它将不起作用。 使用仅比较该对的第二个元素的函子无济于事。 如果您首先将make_pair(1, 1)
插入该集合,然后尝试插入make_pair(2, 1)
,则不会插入第二对,因为该集合将两对视为相同。 您可以在 Ideone 上看到这种效果。
我刚刚在我的 c++ 书中做了一个类似的问题。 我想出的答案可能不是很有效:
int main()
{
string s;
map<string, int> counters;
while(cin >> s)
++counters[s];
//Get the largest and smallest values from map
int beginPos = smallest_map_value(counters);
int endPos = largest_map_value(counters);
//Increment through smallest value to largest values found
for(int i = beginPos; i <= endPos; ++i)
{
//For each increment, go through the map...
for(map<string, int>::const_iterator it = counters.begin(); it != counters.end(); ++it)
{
//...and print out any pairs with matching values
if(it->second == i)
{
cout << it->first << "\t" << it->second << endl;
}
}
}
return 0;
}
//Find the smallest value for a map<string, int>
int smallest_map_value(const map<string, int>& m)
{
map<string, int>::const_iterator it = m.begin();
int lowest = it->second;
for(map<string, int>::const_iterator it = m.begin(); it != m.end(); ++it)
{
if(it->second < lowest)
lowest = it->second;
}
return lowest;
}
//Find the largest value for a map<string, int>
int largest_map_value(const map<string, int>& m)
{
map<string, int>::const_iterator it = m.begin();
int highest = it->second;
for(map<string, int>::const_iterator it = m.begin(); it != m.end(); ++it)
{
if(it->second > highest)
highest = it->second;
}
return highest;
}
创建另一个映射,提供一个基于非键值的 less() 函数,如果 value1 <= value2(不是严格的 < ),该函数应该返回 true。 在这种情况下,也可以对具有非不同值的元素进行排序。
我在thispointer 中找到了这个。 该示例按所有 int 值对 std::map<std::string,int> 进行排序。
#include <map>
#include <set>
#include <algorithm>
#include <functional>
int main() {
// Creating & Initializing a map of String & Ints
std::map<std::string, int> mapOfWordCount = { { "aaa", 10 }, { "ddd", 41 },
{ "bbb", 62 }, { "ccc", 13 } };
// Declaring the type of Predicate that accepts 2 pairs and return a bool
typedef std::function<bool(std::pair<std::string, int>, std::pair<std::string, int>)> Comparator;
// Defining a lambda function to compare two pairs. It will compare two pairs using second field
Comparator compFunctor =
[](std::pair<std::string, int> elem1 ,std::pair<std::string, int> elem2)
{
return elem1.second < elem2.second;
};
// Declaring a set that will store the pairs using above comparision logic
std::set<std::pair<std::string, int>, Comparator> setOfWords(
mapOfWordCount.begin(), mapOfWordCount.end(), compFunctor);
// Iterate over a set using range base for loop
// It will display the items in sorted order of values
for (std::pair<std::string, int> element : setOfWords)
std::cout << element.first << " :: " << element.second << std::endl;
return 0;
}
在某些情况下可以做的一件事是使用vector<pair<int, int>>
而不是使用maps<int, int>
。 这样你就失去了使用 map 的好处,例如更少的查找时间,但你可以直接使用带有 vector<pair<int, int>> 的比较器 function
bool compare(pair<int, int> a, pair<int, int> b)
{
return (a.second < b.second);
}
最近不得不这样做。 我最终使用了指针......
#include <iostream>
#include <type_traits>
#include <algorithm>
#include <map>
#include <vector>
using map_t = std::map<int,int>;
const map_t m
{
{ 5, 20 },
{ -18, 28 },
{ 24, 49 },
{ 17, 27 },
{ 23, 46 },
{ 8, 16 },
{ -13, 11 },
{ -22, 32 },
{ 12, 45 },
{ -2, 19 },
{ 21, 11 },
{ -12, 25 },
{ -20, 8 },
{ 0, 29 },
{ -5, 20 },
{ 13, 26 },
{ 1, 27 },
{ -14, 3 },
{ 19, 47 },
{ -15, 17 },
{ 16, 1 },
{ -17, 50 },
{ -6, 40 },
{ 15, 24 },
{ 9, 10 }
};
template<typename T>
void sort_values_using_vector(T const& m)
{
using map_t = T;
using sort_t = std::vector<std::pair<typename map_t::key_type,
typename map_t::mapped_type>>;
sort_t sorted{ m.begin(), m.end() };
std::sort(sorted.begin(), sorted.end(),
[](auto const& lhs, auto const& rhs)
{
return lhs.second < rhs.second;
});
}
template<typename T>
void sort_values_using_multimap(T const& m)
{
using map_t = T;
using sort_t = std::multimap<typename map_t::mapped_type,
typename map_t::key_type>;
sort_t sorted;
for (auto const& kv : m)
{
sorted.insert(std::make_pair(kv.second, kv.first));
}
}
template<typename T>
void sort_values_using_ptrs(T const& m)
{
using map_t = T;
using ptr_t = std::add_pointer_t
<std::add_const_t<typename map_t::value_type>>;
using sort_t = std::vector<ptr_t>;
sort_t sorted;
sorted.reserve(m.size());
for (auto const& kv : m)
{
sorted.push_back(std::addressof(kv));
}
std::sort(sorted.begin(), sorted.end(),
[](auto const& lhs, auto const& rhs)
{
return lhs->second < rhs->second;
});
}
template<typename T>
void sort_values_using_refs(T const& m)
{
using map_t = T;
using ref_t = std::reference_wrapper
<std::add_const_t<typename map_t::value_type>>;
using sort_t = std::vector<ref_t>;
sort_t sorted{ m.begin(), m.end() };
std::sort(sorted.begin(), sorted.end(),
[](auto const& lhs, auto const& rhs)
{
return lhs.get().second < rhs.get().second;
});
}
static void copy_to_vector(benchmark::State& state) {
// Code inside this loop is measured repeatedly
for (auto _ : state) {
sort_values_using_vector(m);
}
}
BENCHMARK(copy_to_vector);
static void copy_flipped_to_multimap(benchmark::State& state) {
// Code inside this loop is measured repeatedly
for (auto _ : state) {
sort_values_using_multimap(m);
}
}
BENCHMARK(copy_flipped_to_multimap);
static void copy_ptrs_to_vector(benchmark::State& state) {
// Code inside this loop is measured repeatedly
for (auto _ : state) {
sort_values_using_ptrs(m);
}
}
BENCHMARK(copy_ptrs_to_vector);
static void use_refs_in_vector(benchmark::State& state) {
// Code inside this loop is measured repeatedly
for (auto _ : state) {
sort_values_using_refs(m);
}
}
BENCHMARK(use_refs_in_vector);
此代码使用自定义排序功能按值对地图进行排序
#include <iostream>
#include <algorithm>
#include <utility>
#include <iterator>
#include <vector>
#include <map>
using namespace std;
// Comparator function to sort pairs
// according to value
bool comp(pair<int, int>& a,
pair<int, int>& b)
{
return a.second < b.second;
}
// Function to sort the map according
// to value in a (key-value) pair
void customSort(map<int, int>& m)
{
vector<pair<int, int>> a;
for(auto x:m)
a.push_back(make_pair(x.first,x.second));
sort(a.begin(), a.end(), comp);
for (auto x:a) {
cout << x.first<<" "<<x.second<<endl;
}
}
int main()
{
map<int, int> m;
m[1] = 10;
m[2] = 5;
m[4] = 6;
m[6] = 1;
customSort(m);
return 0;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.