As 我猜测 https://stackoverflow.com/a/28330291/85371,这里有一个“高级”方法。
Boost ICL 容器不仅仅是“美化的间隔起点/终点对”的容器。它们旨在实现只是以一般优化的方式进行组合、搜索的业务。
So you不必。
如果你让图书馆做它应该做的事情:
using TimePoint = unsigned;
using DownTimes = boost::icl::interval_set<TimePoint>;
using Interval = DownTimes::interval_type;
using Records = std::vector<DownTimes>;
使用功能域 typedef 需要更高层次的方法。现在,让我们问一个假设的“业务问题”:
我们实际上想如何处理每个位置的停机时间记录?
嗯,我们本质上想要
- 统计所有可辨别的时间段并
- 过滤那些计数至少为 2 的内容
- 最后,我们想显示剩余的“合并”时间段。
好的,工程师:实施吧!
-
唔。统计。它能有多难?
❕ 优雅解决方案的关键是选择正确的数据结构
using Tally = unsigned; // or: bit mask representing affected locations?
using DownMap = boost::icl::interval_map<TimePoint, Tally>;
现在只是批量插入:
// We will do a tally of affected locations per time slot
DownMap tallied;
for (auto& location : records)
for (auto& incident : location)
tallied.add({incident, 1u});
-
好吧,我们来过滤一下。我们只需要适用于 DownMap 的谓词,对吧
// define threshold where at least 2 locations have an outage
auto exceeds_threshold = [](DownMap::value_type const& slot) {
return slot.second >= 2;
};
-
合并时间段!
实际上。我们只是创建另一个 DownTimes 集,对吧。只是,这次不是每个地点。
数据结构的选择再次获胜:
// just printing the union of any criticals:
DownTimes merged;
for (auto&& slot : tallied | filtered(exceeds_threshold) | map_keys)
merged.insert(slot);
Report!
std::cout << "Criticals: " << merged << "\n";
请注意,我们在任何地方都没有接近操纵数组索引、重叠或非重叠间隔、闭合或开放边界。或者,[eeeeek!] 集合元素的强力排列。
我们只是陈述了我们的目标,然后让图书馆来做这项工作。
完整演示
Live On Coliru http://coliru.stacked-crooked.com/a/751b55cbee1ba293
#include <boost/icl/interval_set.hpp>
#include <boost/icl/interval_map.hpp>
#include <boost/range.hpp>
#include <boost/range/algorithm.hpp>
#include <boost/range/adaptors.hpp>
#include <boost/range/numeric.hpp>
#include <boost/range/irange.hpp>
#include <algorithm>
#include <iostream>
#include <vector>
using TimePoint = unsigned;
using DownTimes = boost::icl::interval_set<TimePoint>;
using Interval = DownTimes::interval_type;
using Records = std::vector<DownTimes>;
using Tally = unsigned; // or: bit mask representing affected locations?
using DownMap = boost::icl::interval_map<TimePoint, Tally>;
// Just for fun, removed the explicit loops from the generation too. Obviously,
// this is bit gratuitous :)
static DownTimes generate_downtime(int j) {
return boost::accumulate(
boost::irange(0, 5),
DownTimes{},
[j](DownTimes accum, int i) { return accum + Interval::closed((i*10), ((i*10) + 5 - j)); }
);
}
int main() {
// Initializing data for test
using namespace boost::adaptors;
auto const records = boost::copy_range<Records>(boost::irange(0,4) | transformed(generate_downtime));
for (auto location : records | indexed()) {
std::cout << "Location " << (location.index()+1) << " " << location.value() << std::endl;
}
// We will do a tally of affected locations per time slot
DownMap tallied;
for (auto& location : records)
for (auto& incident : location)
tallied.add({incident, 1u});
// We will combine them so we get an interval_set defined for those periods
// where at least 2 locations have an outage
auto exceeds_threshold = [](DownMap::value_type const& slot) {
return slot.second >= 2;
};
// just printing the union of any criticals:
DownTimes merged;
for (auto&& slot : tallied | filtered(exceeds_threshold) | map_keys)
merged.insert(slot);
std::cout << "Criticals: " << merged << "\n";
}
哪个打印
Location 1 {[0,5][10,15][20,25][30,35][40,45]}
Location 2 {[0,4][10,14][20,24][30,34][40,44]}
Location 3 {[0,3][10,13][20,23][30,33][40,43]}
Location 4 {[0,2][10,12][20,22][30,32][40,42]}
Criticals: {[0,4][10,14][20,24][30,34][40,44]}