我有两个已排序的std::vector<double>
个容器。现在我需要将两个向量合并到一个新的已排序容器中,并带有限制,
当且仅当std::fabs(a-b)<1.e-6
成立时,才应认为这两个值相等。这个问题在我们的网站中出现了很多次
代码和我正在寻找最好的解决方案。
我的第一次尝试是:
std::vector<double> mergeTimeLists(const std::vector<double>& sorted1, const std::vector<double>& sorted2) {
auto cmp = [&](double a, double b)->bool { return std::fabs(a - b) > 1e-6 && a < b; };
std::set<double, decltype(cmp)> set(cmp);
std::copy(sorted1.begin(), sorted1.end(), std::inserter(set, set.begin()));
std::copy(sorted2.begin(), sorted2.end(), std::inserter(set, set.begin()));
std::vector<double> ret;
std::copy(set.begin(), set.end(), std::back_inserter(ret));
return ret;
}
在再次咨询STL的文档后,我提出了:
std::vector<double> mergeTimeLists1(const std::vector<double>& sorted1, const std::vector<double>& sorted2) {
std::vector<double> ret;
std::merge(sorted1.begin(), sorted1.end(), sorted2.begin(), sorted2.end(), std::back_inserter(ret));
ret.erase(std::unique(ret.begin(), ret.end(), [&](double a, double b)->bool { return std::fabs(a - b) < 1e-6; }),ret.end());
return ret;
}
这是我的测试:
int main(int argc, char** args) {
{
auto ret = mergeTimeLists({ 0,0.1,0.2,0.3,0.34 }, { 0.05,0.10000001 });
std::copy(ret.begin(), ret.end(), std::ostream_iterator<double>(std::cout, " "));
}
std::cout << std::endl;
{
auto ret = mergeTimeLists1({ 0,0.1,0.2,0.3,0.34 }, { 0.05,0.10000001 });
std::copy(ret.begin(), ret.end(), std::ostream_iterator<double>(std::cout, " "));
}
}
有没有人有改进的想法?
修订问题
看来,我无法完全清楚明确地陈述我的问题。事实证明,我真正想要的是略有不同。
假设我有两个已排序的std::vector<double>
容器s1
和s2
。我想创建一个新的排序容器s
,其中包含s1
中的所有值和s2
中的一些值,而来自v
的值s2
仅包含在s
当且仅当u
中没有值s1
时,std::fabs(u-v)<1e-6
。
因此,如果s2
中的某些值不太接近,我只希望s
的值位于结果容器s1
中。
我很抱歉没有事先说清楚我的问题,而且我对目前已经得到的反馈感到非常高兴。也许我还能从这里得到什么想法?
答案 0 :(得分:1)
对矢量进行排序。结果也是一个有序的向量。
使用std::merge()
是一个良好的开端,但您的示例在两个方面达不到最佳效果:
第一个问题很简单:
ret.reserve(std::max(sorted1.size(), sorted2.size()));
第二个可以通过改变给std::merge()
的输出迭代器来解决。而不是std::back_inserter(ret)
,而是创建自己的unique_inserter(ret)
,如下所示:
struct unique_inserter
: std::back_insert_iterator<std::vector<double>>
{
typedef std::back_insert_iterator<std::vector<double>> base;
unique_inserter(std::vector<double>& out) : base(out) {}
unique_inserter& operator=(const double& value)
{
if (container->empty() || std::fabs(container->back() - value) > 1e-6)
container->push_back(value);
return *this;
}
// remove this if not using C++11
unique_inserter& operator=(const double&& value)
{
if (container->empty() || std::fabs(container->back() - value) > 1e-6)
container->push_back(std::move(value));
return *this;
}
};
这与std::back_inserter
类似,但如果新值等同于最后一个值,则不执行任何操作。这样,永远不会插入不需要的值,也不需要在以后擦除。