Как я могу сортировать карту STL по значению?
Как я могу реализовать сортировку карт 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
Как я могу сортировать карту таким образом? Есть ли способ, которым я могу справиться с ключом и значением с отсортированными значениями?
Ответы
Ответ 1
Вы можете создать вторую карту с первыми значениями карты в качестве ключей и первых клавиш карты в качестве значений.
Это работает только в том случае, если все значения различны. Если вы не можете этого допустить, вам нужно создать мультимап вместо карты.
Ответ 2
Сначала выгрузите все пары ключ-значение в set<pair<K, V> >
, где set
построена с менее чем функтором, который сравнивает только пару второго значения. Таким образом, ваш код все еще работает, даже если ваши значения не все разные.
Или сбрасывать пары ключ-значение в vector<pair<K, V> >
, а затем сортировать этот вектор с тем же менее чем функтором впоследствии.
Ответ 3
Интересно, как я могу реализовать сортировку по STL по значению.
Вы не можете, по определению. Карта - это структура данных, которая сортирует свой элемент по ключу.
Ответ 4
Вы должны использовать Boost.Bimap для такого рода вещей.
Ответ 5
Я только что сделал аналогичный вопрос в моей книге на С++. Ответ, который я придумал, может быть не очень эффективным:
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;
}
Ответ 6
Основываясь на идее @swegi, я внедрил решение в С++ 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.
Код на Ideone
Я также реализовал решение С++ 11 на основе идеи @Chris, используя вектор пар. Для правильной сортировки я предоставляю 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 об использовании набора пар. Однако это не сработает, если значения не все различны. Использование функтора, который сравнивает только второй элемент пары, не помогает. Если вы сначала введете make_pair(1, 1)
в набор, а затем попытаетесь вставить make_pair(2, 1)
, тогда вторая пара не будет вставлена, потому что обе пары считаются идентичными этому набору. Вы можете увидеть этот эффект здесь, на Ideone.
Ответ 7
Создайте еще одну карту, предоставите функцию less(), основанную на значении not key, и функция должна вернуть true, если значение1 < = значение2 (не строго <). В этом случае элементы с нечеткими значениями также могут быть отсортированы.
Ответ 8
Я нашел это в этом указателе. В примере сортируется std :: map <std :: string, int> по всем значениям 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;
}