【问题标题】:Map a range of values to a single value将一系列值映射到单个值
【发布时间】:2015-08-12 17:55:54
【问题描述】:

我需要将lowerBoundupperBound 之间的值映射到某个值。

说明性示例:

例如,假设我有用户订阅的 GPS 系统。该系统能够为我提供用户与某个点的距离。根据用户的距离,我想为他们分配一个 ID。

因此用户远离

  • 1100 得到 ID: 8.4
  • 101200 得到 ID: 7.2
  • 201300 得到 ID: 3.6
  • 401600 得到 ID: 4.1

等等……

我的方法:

所以我做了什么,我通过如下初始化创建了一个std::map

   std::map<int, double> distanceToIdMap; 

   distanceToIdMap =
    {
            {100, 8.4},
            {200, 7.2},
            {300, 3.6},
    };

然后我使用此代码获取给定距离的 ID:

double roundUpToHundred = std::ceil(realDistance / 100.0) * 100;
double powerForDistance = distanceToIdMap.at(roundUpToHundred);

但是,对于401600 的距离,我的方法失效了,因为对于400+ 的距离,我得到了500 的值,因为我没有进入该值地图。当然,简单的解决方案是将500 的条目添加到distanceToIdMap,但这不是我想要处理这个问题的方式。

我想要一张带有{(lowerbound, upperbound) , correspondingID} 结构的地图,这样我就可以解决 ID 覆盖距离超过 100m 的情况。并且给定的可以检查lowerBound realDistance upperBound 然后提供ID。

【问题讨论】:

  • 您想要映射中的漏洞吗?如果不是,则不必为每个范围提供开头和结尾,结尾应等于下一个范围的开头。

标签: c++ c++11


【解决方案1】:

这听起来像是std::lower_bound 的用例。请注意lower_bound 是正确的实现,而不是upper_bound。此代码编译并工作。 map 不需要排序,因为它已经排序。这应该在 O(log(N)) 中运行。

您需要捕获异常...

#include <iostream>
#include <algorithm>
#include <map>
#include <stdexcept>

using namespace std;

std::map<int, double> distanceToIdMap =
    {
            {100, 8.4},
            {200, 7.2},
            {300, 3.6},
            {600, 4.1}
    };   

double Distance(int user)
{
    auto x = std::lower_bound(distanceToIdMap.begin(), distanceToIdMap.end(), std::pair<const int,double>(user,0));
    if (x == distanceToIdMap.end()) throw std::runtime_error("can't find");
    return x->second;
}

int main()
{
    for(int user=25;user < 650;user+=25)
    {
        cout << user << " " << Distance(user) << std::endl;
    }
   return 0;
}

输出:

sh-4.3# g++ -o main *.cpp -std=c++11                                                                                                                                                                                                                    
main                                                                                                                                                                                                                                                    
sh-4.3# main                                                                                                                                                                                                                                            
25 8.4                                                                                                                                                                                                                                                  
50 8.4                                                                                                                                                                                                                                                  
75 8.4                                                                                                                                                                                                                                                  
100 8.4                                                                                                                                                                                                                                                 
125 7.2                                                                                                                                                                                                                                                 
150 7.2                                                                                                                                                                                                                                                 
175 7.2                                                                                                                                                                                                                                                 
200 7.2                                                                                                                                                                                                                                                 
225 3.6                                                                                                                                                                                                                                                 
250 3.6                                                                                                                                                                                                                                                 
275 3.6                                                                                                                                                                                                                                                 
300 3.6                                                                                                                                                                                                                                                 
325 4.1                                                                                                                                                                                                                                                 
350 4.1                                                                                                                                                                                                                                                 
375 4.1                                                                                                                                                                                                                                                 
400 4.1                                                                                                                                                                                                                                                 
425 4.1                                                                                                                                                                                                                                                 
450 4.1                                                                                                                                                                                                                                                 
475 4.1                                                                                                                                                                                                                                                 
500 4.1                                                                                                                                                                                                                                                 
525 4.1                                                                                                                                                                                                                                                 
550 4.1                                                                                                                                                                                                                                                 
575 4.1                                                                                                                                                                                                                                                 
600 4.1                                                                                                                                                                                                                                                 
terminate called after throwing an instance of 'std::runtime_error'                                                                                                                                                                                     
  what():  can't find                                                                                                                                                                                                                                   
Aborted (core dumped)                                                                                                                                                                                                                                   
sh-4.3# main                                                                                                                                                                                                                                            

【讨论】:

  • 在我接受答案之前需要澄清几个问题:1) 这种方法与@pascx64 答案中给出的map::upper_bound 有何不同? 2)(出于好奇)将double Distance(int user) 函数命名为大写Distance 是否有特定原因? 3)std::pair&lt;const int,double&gt;(user,0)的作用是什么
  • 1) 这相当于使用map::lower_bound的那些;我不知道 map 直接支持lower_bound,所以我使用通用函数来执行相同的操作。另一个答案更简单 2)我的命名约定对所有函数或方法都使用大写字母。 3)pair是比较对象。 map 对象是pairs 的可迭代列表,并按该对的first(键)排序。
  • map::lower_bound 存在是因为std::lower_bound 在应用于map 时效率低-它没有随机访问迭代器。 总是在成员函数存在时使用它。
【解决方案2】:

使用std::map::lower_boundboost::optional,您可以执行以下操作:

const std::map<int, boost::optional<double>> distanceToIdMap =
{
    {0, boost::none},
    {100, 8.4},
    {200, 7.2},
    {300, 3.6},
    {400, boost::none},
    {600, 4.1}
};

for (auto v : {-10, 50, 99, 100, 101, 250, 350, 500, 601})
{
    auto it = distanceToIdMap.lower_bound(v);

    if (it != distanceToIdMap.end() && it->second) {
        std::cout << v << " " << *it->second << std::endl;
    } else {
        std::cout << v << " None" << std::endl;
    }
}

Live example

【讨论】:

    【解决方案3】:

    试试upper_bound

     auto upper  = distanceToIdMap.upper_bound( 50 );
     std::cout << "value:" << upper->second << std::endl;
    

    http://www.cplusplus.com/reference/map/map/upper_bound/

    【讨论】:

    • 对于我在问题中的地图,如果我这样做会发生什么distanceToIdMap.upper_bound( 312 );
    • 它将采用 401 to 600 范围,因为您没有在 300 和 401 之间输入任何值(我不确定您的问题是否有误?)
    【解决方案4】:

    完全避开地图怎么样?

    std::vector<std::pair<double, double>> table =
    {
        {0, 0},
        {94.5, 2.1},
        {314.4, 4.7}
    } ;
    
    double distance = ...
    double value = std::upper_bound(table.begin(), table.end(), std::pair(distance, 0)) ;
    

    缺点:表格必须正确排序。

    【讨论】:

    • 我想你忘记了std::pair(distance, 0) 中的模板,应该是std::pair&lt;double,double&gt;( distance, 0.0 )
    • 是的,或者我可以使用 std::make_pair(distance, 0.0) ;
    • upper_bound 返回迭代器不是 double
    【解决方案5】:

    这是一个简单的解决方案:

    int mapdistance[] = {100,200,300};
    double mapid[] = {8.4,7.2,3.6};
    double dist=0;
    for(int i=0;i<sizeof(mapdistance)/sizeof(int);i++) {
       dist += mapdistance[i];
       if (realdistance<=dist) return mapid[i];
    }
    

    【讨论】:

    • 如果您保持排序,如果您的 mapdistance 数组开始变大,您也可以在边界检查中使用二进制搜索。当然,这是针对 C++ 陈述的问题的非常 C 的解决方案 :)
    • 什么意思?它在 C++ 中编译 :) 所问的问题已经对值进行了排序,所以我认为它们会继续这种方式。我的系统是线性搜索的 (N) 并且不能使用二进制文件,因为我要为每个 mapdistance 将值添加到 dist。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-03
    • 1970-01-01
    相关资源
    最近更新 更多