How to make a map sort by value C++

这一生的挚爱 提交于 2021-02-05 12:23:07

问题


I was trying to make a map sort by value using a custom comparator but I couldn't figure out why I kept getting the error of "no matching call to compareByVal"

Here's what I had in my main.cpp:

#include <map>
#include <iostream>

struct compareByVal {
  bool operator[](const std::pair<int,int> & a, const std::pair<int,int> & b)
    return a.second < b.second;
}

int main() {
  std::map<int,int,compareByVal> hash;
  hash[1] = 5;
  hash[2] = 2;
  hash[3] = 10;

  std::cout << hash.begin()->first << std::endl;
}

回答1:


The first, simple problem is

struct compareByVal {
  bool operator[](const std::pair<int,int> & a, const std::pair<int,int> & b)
    return a.second < b.second;
}

should be

struct compareByVal {
  bool operator()(const std::pair<int,int> & a, const std::pair<int,int> & b) const {
    return a.second < b.second;
  }
};

The second, serious problem is the signature of the compare is wrong. It should be

struct compareByVal {
  bool operator()(const int leftKey, const int rightKey) const;
}

You can't access the value in the compare function. There is no (simple) way to sort a map by value.




回答2:


Simply put, you cannot. Not sure which compiler you're using, but clang and gcc both give useful messages. with context.

clang: static_assert(__is_invocable<_Compare&, const _Key&, const _Key&>{},

gcc: if (__i == end() || key_comp()(__k, (*__i).first))

You can see that clang and gcc are both calling the compare method with only they key, and not a value. This is simply how maps work.

If you want to sort by value, you would have to create your own custom map, or, more realistically, use the value as the key instead. Creating your own map to achieve this would be more difficult than you'd think, since it would have to sort after any value is modified.




回答3:


Well, first, the reason you're getting the error: "no matching call to compareByVal" is because map's comparator works only with the keys. So the comparator should like:

struct compareByVal {
  template <typename T>
  bool operator()(const T& a, const T& b) const
    return a < b;
}

Coming on to what you want to achieve, I see two ways of doing so:

  1. Copy all the elements of the map to a std::vector and sort that:
std::vector<std::pair<int,int> > v(hash.begin(), hash.end());
std::sort(v.begin(), v.end(), [](const auto& a, const auto& b) { return a.second < b.second; });
  1. Copy all the elements of the map to another map with keys as values and values as keys. If values of your map are not unique, you can use a std::multimap instead.



回答4:


If you want to sort a std::map by its value, then you are using the wrong container. std::map is sorted by the keys by definition.

You can wrap key and value:

struct foo {
    int key;
    int value;
};

and then use a std::set<foo> that uses a comparator that only compares foo::value.




回答5:


This may be an X-Y issue.

If you need to sort by both key and value, then a single std::map may not be the most efficient choice.

In database theory, all the data would be placed into a single table. An index table would be created describing the access or sorting method. Data that needs to be sorted in more than one method would have multiple index tables.

In C++, the core table would be a std::vector. The indices would be std::map<key1, vector_index>, std::map<key2, vector_index>, where vector_index is the index of the item in the core table.

Example:

struct Record
{
  int age;
  std::string name;
};

// Core table
std::vector<Record> database;

// Index by age
std::map<int, unsigned int> age_index_table;

// Index by name
std::map<std::string, unsigned int> name_index_table;

// Fetching by age:
unsigned int database_index = age_index_table[42];
Record r = database[database_index];

// Fetching by name:
unsigned int database_index = name_index_table["Harry Potter"];
Record r = database[database_index];

You can learn more by searching the internet for "database index tables c++".

If it looks like a database and smells like a database ...



来源:https://stackoverflow.com/questions/60098150/how-to-make-a-map-sort-by-value-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!