我有一个文件名列表,每个文件名代表一个时间点。该列表通常包含数千个元素。给定一个时间点,我想将这些文件名转换为时间对象(我正在使用boost::ptime
),然后根据文件名找到此时间点的std::lower_bound
的值
示例:
文件名(日期+时间,分钟增加,每个文件都有一分钟):
station01_20170612_030405.hdf5
station01_20170612_030505.hdf5
station01_20170612_030605.hdf5
station01_20170612_030705.hdf5
station01_20170612_030805.hdf5
station01_20170612_030905.hdf5
如果我有一个时间点2017-06-12 03:06:00
,那么它适合这里:
station01_20170612_030405.hdf5
station01_20170612_030505.hdf5
<--- The lower bound I am looking for is here
station01_20170612_030605.hdf5
station01_20170612_030705.hdf5
station01_20170612_030805.hdf5
station01_20170612_030905.hdf5
到目前为止,一切都很简单。现在问题是文件列表可能掺杂了一些无效的文件名,这将使转换到一个时间点失败。
目前,我这样做是简单/低效的方式,我想优化它,因为这个程序将在服务器上运行并且操作成本很重要。所以,愚蠢的方法是:创建一个包含时间点的新列表,并且只推送有效的时间点:
vector<ptime> filesListTimePoints;
filesListTimePoints.reserve(filesList.size());
ptime time;
for(long i = 0; i < filesList.size(); i++) {
ErrorCode error = ConvertToTime(filesList[i], time);
if(error.errorCode() == SUCCESS)
filesListTimePoints.push_back(time);
}
//now use std::lower_bound() on filesListTimePoints
你知道,问题在于我使用的是线性解决方案,其问题可以通过O(log(N))
复杂度来解决。我不需要转换所有文件,甚至不需要查看所有文件!
我的问题:我如何将其嵌入std::lower_bound
,以保持最佳复杂性?
在cppreference上,有std::lower_bound
的基本实现。我正在考虑修改它以获得一个有效的解决方案。但是我不确定当一个转换失败时该怎么做,因为这个算法高度依赖于单调行为。这个问题是否有解决方案,即使在数学上也是如此?
这是我最初想到的版本:
template<class ForwardIt, class T>
ForwardIt lower_bound(ForwardIt first, ForwardIt last, const T& value)
{
ForwardIt it;
typename std::iterator_traits<ForwardIt>::difference_type count, step;
count = std::distance(first, last);
while (count > 0) {
it = first;
step = count / 2;
std::advance(it, step);
ErrorCode error = ConvertToTime(*it, time);
if(error.errorCode() == SUCCESS)
{
if (*it < value) {
first = ++it;
count -= step + 1;
}
else
count = step;
}
else {
// skip/ignore this point?
}
}
return first;
}
我的终极解决方案(可能听起来很愚蠢)是让这个方法成为列表的变异器,并擦除无效的元素。有更清洁的解决方案吗?
答案 0 :(得分:2)
您只需按optional<ptime>
索引即可。如果要缓存转换后的值,请考虑将其设为multimap<optional<ptime>, File>
。
更好的是,创建一个表示文件的数据类型,并计算其构造函数中的时间点:
struct File {
File(std::string fname) : _fname(std::move(fname)), _time(parse_time(_fname)) { }
boost::optional<boost::posix_time::ptime> _time;
std::string _fname;
static boost::optional<boost::posix_time::ptime> parse_time(std::string const& fname) {
// return ptime or boost::none
}
};
现在,只需适当地定义operator<
或使用例如boost :: multi_index_container索引_time
补充说明:
lower_bound
,upper_bound
和equal_range
操作,并且显然也可以工作与std::lower_bound
和朋友们合作。filter_iterator
适配器:http://www.boost.org/doc/libs/1_64_0/libs/iterator/doc/filter_iterator.html