【问题标题】:How to make a map sort by value C++如何使地图按值排序 C++
【发布时间】:2020-02-06 15:13:21
【问题描述】:

我试图使用自定义比较器按值排序地图,但我无法弄清楚为什么我一直收到“没有匹配的 compareByVal 调用”的错误

这是我在 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;
}

【问题讨论】:

  • 因为它不关心值。它只会传递密钥。除非您制作自己的自定义地图,否则您无法按值排序。或者,你知道,只是让价值成为关键?在您的示例中,hash[1] = 5 实际上插入了{1,0},然后在分配之后将0 更改为5。你会如何排序?
  • operator[]应该是operator()
  • 地图基本上是按键排序的。您可以通过比较器更改这些键的排序方式,但顺序必须基于键。编辑:如果您想按值排序并查找键,您可能想要交换您认为的键和您认为的值。
  • 恕我直言,如果要按键和按值排序,请使用std::vector 和两个映射。第一个映射将是 ,第二个映射将是 。这是一种数据库技术:一个表和一个或多个索引表中的所有数据。
  • 我试图使用自定义比较器按值排序 -- 听起来像XY Problem。你真正想解决什么问题?

标签: c++ dictionary comparator


【解决方案1】:

第一个简单的问题是

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

应该是

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

第二个严重的问题是比较的签名是错误的。应该是

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

您无法访问比较函数中的值。没有(简单的)方法可以按值对地图进行排序。

【讨论】:

    【解决方案2】:

    简单地说,你不能。不确定您使用的是哪个编译器,但 clang 和 gcc 都提供了有用的消息。有上下文。

    叮当声: static_assert(__is_invocable&lt;_Compare&amp;, const _Key&amp;, const _Key&amp;&gt;{},

    海合会: if (__i == end() || key_comp()(__k, (*__i).first))

    您可以看到 clang 和 gcc 都在调用 compare 方法,只有它们的 ,而不是值。这就是地图的工作原理。

    如果您想按值排序,则必须创建自己的自定义地图,或者更实际地使用值作为键。创建自己的地图来实现这一点比您想象的要困难,因为它必须在修改任何值后进行排序。

    【讨论】:

      【解决方案3】:

      如果您想按其值对std::map 进行排序,那么您使用了错误的容器。 std::map 按定义按键排序。

      您可以包装键和值:

      struct foo {
          int key;
          int value;
      };
      

      然后使用一个std::set&lt;foo&gt;,它使用一个只比较foo::value的比较器。

      【讨论】:

        【解决方案4】:

        首先,您收到错误的原因是:“没有对 compareByVal 的匹配调用”是因为 map 的比较器仅适用于键。所以比较器应该是这样的:

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

        谈到你想要实现的目标,我看到了两种方法:

        1. 将地图的所有元素复制到 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. 将映射的所有元素复制到另一个映射,其中键作为值,值作为键。如果您的地图值不是唯一的,您可以使用 std::multimap 代替。

        【讨论】:

          【解决方案5】:

          这可能是 X-Y 问题。

          如果您需要同时按键和值进行排序,那么单个std::map 可能不是最有效的选择。

          在数据库理论中,所有数据都将放在一个表中。将创建一个索引表来描述访问或排序方法。需要以一种以上方法排序的数据将具有多个索引表。

          在 C++ 中,核心表是 std::vector。索引将是std::map&lt;key1, vector_index&gt;std::map&lt;key2, vector_index&gt;,其中vector_index 是核心表中项目的索引。

          例子:

          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];
          

          您可以通过在 Internet 上搜索“数据库索引表 c++”来了解更多信息。

          如果它看起来像数据库,闻起来像数据库......

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2013-01-06
            • 2012-12-04
            • 1970-01-01
            • 1970-01-01
            • 2022-01-06
            • 2019-03-10
            • 2012-04-25
            相关资源
            最近更新 更多