如何按值实现STL地图排序?
例如,我有一张地图m
:
map<int, int> m;
m[1] = 10;
m[2] = 5;
m[4] = 6;
m[6] = 1;
我想按m
的值对该地图进行排序。所以,如果我打印地图,我想得到如下结果:
m[6] = 1
m[2] = 5
m[4] = 6
m[1] = 10
如何以这种方式对地图进行排序?有什么方法可以用排序值来处理键和值吗?
答案 0 :(得分:61)
首先将所有键值对转储到set<pair<K, V> >
,其中set
使用一个小于函数来构造,该函数只比较该对的第二个值。这样,即使您的值并非完全不同,您的代码仍然有效。
或者将键值对转储到vector<pair<K, V> >
,然后使用相同的小于函子对该向量进行排序。
答案 1 :(得分:29)
您可以构建第二个地图,第一个地图的值作为键,第一个地图的键作为值。
仅当所有值都不同时才有效。如果你不能假设这一点,那么你需要建立一个多图而不是地图。
答案 2 :(得分:16)
我想知道如何按值实现STL地图排序。
你不能,按照定义。映射是一种按键对其元素进行排序的数据结构。
答案 3 :(得分:4)
你应该使用Boost.Bimap来做这类事情。
答案 4 :(得分:1)
我刚刚在我的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;
}
答案 5 :(得分:1)
根据@ swegi的想法,我使用multimap
在c++11中实施了一个解决方案:
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&#39;的C ++ 11解决方案。使用矢量对的想法。为了正确排序,我提供了一个lambda expression作为比较函子:
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&#39;关于使用一组对的想法。但是,如果价值观并非完全不同,它就不会起作用。使用仅比较对的第二个元素的仿函数并不起作用。如果您首先将make_pair(1, 1)
插入集合中,然后尝试插入make_pair(2, 1)
,则不会插入第二对,因为这两个对被视为相同。你可以看到效果here on Ideone。
答案 6 :(得分:0)
创建另一个映射,根据值not key提供less()函数,如果value1 &lt; = value2(不严格&lt;),则函数应返回true。在这种情况下,也可以对具有非不同值的元素进行排序。
答案 7 :(得分:0)
我在thispointer中找到了这个。该示例按所有int值对std :: map
#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;
}
答案 8 :(得分:-1)
最近不得不这样做。我最终使用了指针...
#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);
答案 9 :(得分:-1)
此代码使用自定义排序函数按值对地图进行排序
#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;
}