【问题标题】:std::pair as key in mapstd::pair 作为 map 中的键
【发布时间】:2015-03-04 16:03:24
【问题描述】:

我有一个大型图像数据集,是在特定时间拍摄的,其中每个图像捕获 start_timestop_time 都已知并编码为双精度。 我想根据模拟时间将每个连续图像加载到我的模拟中,即 - 检查当前模拟时间何时落在开始/停止间隔内。

我想为此使用地图,其中键是开始和停止时间的std::pair<double, double>,值是图像的完整路径。

std::map<std::pair<double, double>, std::string> _sequence; // t1, t2 and full path

我的问题: 如何搜索这样的地图以查找 _currentTime 是否在间隔对内?

【问题讨论】:

标签: c++ search intervals stdmap


【解决方案1】:

首先,如果搜索包含是您想要做的主要事情,请不要使用map 键入std::pair&lt;double, double&gt;。这不是一个对该数据结构有意义的操作。

但如果你坚持,代码看起来会像这样(在 C++11 中):

bool isWithinInterval() const {
    for (const auto& pr : _sequence) {
        if (_currentTime >= pr.first.first && _currentTime <= pr.first.second) {
            return true;
        }
    }
    return false;
}

Pre-C++11,同样的想法,只是循环语法略有不同。理想情况下,我们会使用std::find_if,但表达地图的value_type 很麻烦。但在 C++14 中,没有这样的麻烦:

auto it = std::find_if(_sequence.begin(),
                       _sequence.end(),
                       [_currentTime](const auto& pr) {
                           return _currentTime >= pr.first.first && _currentTime <= pr.first.second;
                       });
return it != _sequence.end();

或者只是:

return std::any_of(_sequence.begin(), _sequence.end(),
                   [_currentTime](const auto& pr) {
                       return _currentTime >= pr.first.first && _currentTime <= pr.first.second;
                   });

【讨论】:

  • 我实际上是在我应该使用的数据结构上来回循环。你对什么是最佳的和相当快的实施有什么建议吗?我真的很喜欢使用来自 STL 的东西。 (即不写自己的二叉树类)
  • @mike 我认为标准库中没有任何间隔。它实际上只是顺序容器和关联容器。
  • 我想学习-为什么在这种情况下使用地图不好?我对这个问题的任何解决方案持开放态度,只是我或多或少是一个菜鸟,而地图似乎是一种相当简单的方法......
【解决方案2】:

一种方法可能是使用std::map&lt;std::pair&lt;double, double&gt;, std::string&gt;,而是使用std::map&lt;double, std::pair&lt;double, std::string&gt;&gt;:您将使用m.lower_bound(current_time) 来查找current_time 可以适合的一系列元素的开始.然后,您将遍历迭代器,直到它到达末尾、落入相关范围或超出结束时间:

auto it = _sequence.lower_bound(current_time);
for (; it != _sequence.end() && current_time <= it->second; ++it) {
   if (it.first <= current_time) {
       // found a matching element at it
   }
}

使用带有std::pair&lt;double, double&gt; 键的布局会尴尬地需要第二次。不过,您可以使用std::make_pair(current_time, current_time)

【讨论】:

  • 在您的示例中,您的意思是键是 start_time 而第一个是 end_time?
  • 我在问,因为我可能还需要在某个时候存储停止/结束时间,因为我认为需要实际模拟拍摄图像所花费的时间(淡化它在或类似的东西)
  • 是的,关键是开始时间,所有其他数据都存储在记录中。如果这不太符合您的需求,您可能需要查看专门用于处理间隔的范围树。
【解决方案3】:
double search = 0.; /* or some other value */
bool found = false;
for ( auto & key_value_pair : _sequence ) {
    // key_value_pair.first == map key
    // key_value_pair.second == key's associated value
    if ( key_value_pair.first.first <= search || search <= key_value_pair.first.second ) {
        found = true;
        break;
    }
}
if ( found ) {
    /* it's within an interval pair! */
} else {
    /* it's not within an interval pair! */
}

我建议您也关注boost::icl

【讨论】:

    【解决方案4】:

    如果可能,不要使用 std::pair 作为键。作为键并没有真正意义,因为您最终会遇到两个重叠范围映射到同一个元素的情况。

    无论如何,这就是我将如何实施解决此类问题的方法。 lower_bound/upper_bound 是你的朋友。此外,您可以通过在停止时间键入值来避免反向迭代器技巧。

    #include <map>
    #include <stdio.h>
    
    struct ImageStuff
    {
      double startTime;
      double stopTime;
      char data[1000];
    };
    
    typedef std::map<double, ImageStuff> starttime_map_type; 
    starttime_map_type starttime_map;
    
    ImageStuff & MakeImage (double start, double stop) {
      ImageStuff newImage;
      newImage.startTime = start;
      newImage.stopTime = stop;
      return starttime_map[start] = newImage;
    }
    
    starttime_map_type::iterator FindByTime (double time) {
      starttime_map_type::reverse_iterator i = starttime_map_type::reverse_iterator(starttime_map.upper_bound(time));
      if (i == starttime_map.rend() || time > i->second.stopTime) {
        printf ("Didn't find an image for time %f\n", time);
        return starttime_map.end();
      }
      else {
        printf ("Found an image for time %f\n", time);
        return i.base();
      }
      return starttime_map.end();
    }
    
    
    int main (void)
    {
      MakeImage (4.5, 6.5);
      MakeImage (8.0, 12);
      MakeImage (1, 1.2);
    
      auto i = FindByTime(3);
      i = FindByTime(4.5);
      i = FindByTime(9);
      i = FindByTime(15);
    
      return 0;
    }
    

    【讨论】:

    • 给您的问题:我正在尝试实现这一点,但它在return starttime_map[start] = newImage; 上崩溃 - 在使用 MakeImage 函数之前,我是否需要使用 starttime_map 进行初始化或执行其他操作? (否则你在那里写的逐行)
    • 试着把它分解成ImageStuff &amp; result = starttime_map[start]; result = newImage; return result;
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-04
    相关资源
    最近更新 更多