【问题标题】:get range of map elements with equal values获取具有相等值的地图元素范围
【发布时间】:2016-09-28 13:33:42
【问题描述】:

我有一张地图声明为:

std::map< std::pair<int, int>, bool > allPositions; // essentially, keys are just 2D points

我需要获取其值为true的元素的范围

使用std::equal_range

auto range = std::equal_range(allPositions.begin(), allPositions.end(), true);

给出这些错误

错误 C2672 'operator __surrogate_func':没有匹配的重载 功能找到 xutility

错误 C2893 无法专门化函数模板“未知类型” std::less::operator ()(_Ty1 &&,_Ty2 &&) const' xutility

错误 C2056 非法表达式 xutility

错误 C2672 'operator __surrogate_func':没有匹配的重载 函数找到算法

错误 C2893 无法专门化函数模板“未知类型” std::less::operator ()(_Ty1 &&,_Ty2 &&) const' 算法

我想我在这里不需要谓词函数,因为std::pair 已经重载了operator &lt;,否则地图代码将不会被编译

那么如何使用std::equal_range 映射来获得具有相等值的对的范围?

【问题讨论】:

  • 不管怎样,相信你还是需要比较功能的。遍历地图将为您提供键值对,而不仅仅是值。而true 默认情况下无法与std::pair&lt;std::pair&lt;int,int&gt;,bool&gt; 相比。
  • @Altainia 我知道它给出了对,我的意思是获取值相等的地图元素的范围
  • 为此您需要不同的容器,例如 boost::multi_index,std::map 不会根据值为您提供范围。

标签: c++ c++11 visual-c++ stl


【解决方案1】:

我需要获取其true

的元素的范围

您必须迭代映射以获取其值对为true 的迭代器...我有一个工作示例Live On Coliru。像这样的东西可以提升。

template<typename Map,
         typename Value    = typename Map::mapped_type,
         typename Compare  = std::equal_to<Value>,
         typename Iterator = typename Map::iterator>
std::vector<Iterator> equal_values(const Map& mp, const Value& val, Compare cmp = Compare()){
    std::vector<Iterator> rtn;
    for(auto iter = mp.begin(); iter != mp.end(); ++iter)
        if(cmp(iter->second, val))
            rtn.push_back(iter);
    return rtn;
}

或者,您可能想要使用Boost.BimapBoost.MultiIndex

【讨论】:

  • 这不是一个解决方案,因为第一个 std::map::equal_boundkey 作为参数,但我需要获得一系列具有相同值的对,第二个简单的遍历映射效率低下,因为在这种情况下,我可以只使用向量而不是映射来执行快速迭代,这将是线性复杂度,但我需要在对数时间内快速查找
  • @ampawd 使用std::map,快速索引和迭代是单向之旅(key -> value)。通过keys 检索边界是LogN 的事情。无法在 LogN 时间内通过 values 检索边界。 ... 在两个方向上使其 logN 不是 std::map 所做的。但是,通过一些工作,您可以并置两张地图来获得这种行为。这就是为什么我建议使用 Boost.Bimap
【解决方案2】:

那么如何使用 std::equal_range for map 来获得具有相等值的对的范围?

假设您有一张包含以下数据的地图:

{ {{0,0},false}, {{1,1},true}, {{2,2},false}, {{3,3},true} };

您期望 true 的相等范围返回什么?为false?

为此,您的容器必须根据您用于获取范围的标准进行分区。 std::map 绝对不是按值获取范围的容器。因此,您需要将数据或迭代器复制到不同的容器中并相应地对其进行排序并使用该容器来获取您的范围,或者通过过滤动态创建这样的容器。或者您可以使用像boost::bimapboost::multi_index 这样可以提供多个索引的容器。

【讨论】:

    【解决方案3】:

    假设你有一张这样的地图:

    using point = std::pair<int,int>;
    std::map<point,bool> my_map;
    

    假设您在其中有一些值:

    my_map = { {{0,0},false}, {{0,1},true}, {{1,0},true}, {{1,1},false} };
    

    现在让我们看看这个映射的第一个迭代器在被取消引用时会是什么:

    {{0,0},false}
    

    当您使用 std::equal_range(my_map.begin(), my_map.end(), true); 时,您要求将 true 检查到取消引用的迭代器。但是取消引用的迭代器不是布尔值。这是一对点和布尔值。
    因此,您可能想尝试以下方法:

    using map_iter = std::map<point,bool>::iterator; //is {point,bool}
    auto range = std::equal_range(my_map.begin(), my_map.end(), [](map_iter& iter){
      return iter.second == true;
    };
    

    编辑:
    澄清一下,这将解决编译器错误,但不会解决映射值的逻辑错误,而不是(必然)被排序,以便您可以获得一对定义包含所有匹配值的范围的迭代器作为地图不是按值排序的

    【讨论】:

    • 为此,数据必须按该标准排序。
    • @Slava 是的。这是真的。我想这个答案更多地是为了解决一个误解,即 std::map 的迭代器不会单独取消引用该值。
    • 抱歉,您的回答具有误导性。它可以编译,但您不能将 std::range 与您的 lambda 和此类映射一起使用。
    • 澄清一下?我认为没有必要提供根本性损坏的代码来修复编译错误。
    猜你喜欢
    • 1970-01-01
    • 2015-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-09-24
    • 1970-01-01
    • 2017-07-12
    相关资源
    最近更新 更多