简体   繁体   English

如何使地图按值排序 C++

[英]How to make a map sort by value C++

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"我试图使用自定义比较器按值对地图进行排序,但我无法弄清楚为什么我不断收到“对 compareByVal 没有匹配调用”的错误

Here's what I had in my main.cpp:这是我在 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;
}

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.没有(简单的)方法可以按值对地图进行排序。

Simply put, you cannot.简单地说,你不能。 Not sure which compiler you're using, but clang and gcc both give useful messages.不确定您使用的是哪个编译器,但 clang 和 gcc 都提供了有用的消息。 with context.有上下文。

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

gcc: if (__i == end() || key_comp()(__k, (*__i).first)) 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.您可以看到 clang 和 gcc 都只使用它们的而不是值来调用 compare 方法。 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.创建自己的地图来实现这一点比您想象的要困难,因为它必须在修改任何值后进行排序。

Well, first, the reason you're getting the error: "no matching call to compareByVal" is because map's comparator works only with the keys.好吧,首先,您收到错误的原因是:“没有对 compareByVal 的匹配调用”是因为 map 的比较器仅适用于键。 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::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.如果地图的值不唯一,则可以改用 std::multimap。

If you want to sort a std::map by its value, then you are using the wrong container.如果您想按其值对std::map进行排序,那么您使用的是错误的容器。 std::map is sorted by the keys by definition. std::map根据定义按键排序。

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 .然后使用std::set<foo> ,它使用只比较foo::value的比较器。

This may be an XY issue.这可能是 XY 问题。

If you need to sort by both key and value, then a single std::map may not be the most efficient choice.如果您需要按键和值进行排序,那么单个std::map可能不是最有效的选择。

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 .在 C++ 中,核心表将是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.索引将是std::map<key1, vector_index>std::map<key2, vector_index> ,其中vector_index是核心表中项目的索引。

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++".您可以通过在 Internet 上搜索“数据库索引表 c++”来了解更多信息。

If it looks like a database and smells like a database ...如果它看起来像一个数据库并且闻起来像一个数据库......

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM