[英]Merge two sorted double vectors using different comparision function
I have two sorted std::vector<double>
containers. 我有两个排序的
std::vector<double>
容器。 Now I need to merge both vectors to a new sorted container, with the restriction, that two values should be considered equal if and only if std::fabs(ab)<1.e-6
holds. 现在,我需要将两个向量合并到一个新的排序容器中,但有一个限制,即当且仅当
std::fabs(ab)<1.e-6
成立时,两个值才应视为相等。 This problem pops up plenty of times in our code and I'm looking for the neatest solution. 这个问题在我们的代码中弹出了很多次,我正在寻找最整洁的解决方案。
My first attempt was: 我的第一次尝试是:
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;
}
After consulting again the docs of the STL I came up with: 在再次咨询了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;
}
This is my test: 这是我的测试:
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, " "));
}
}
Does anyone has some ideas for improvements? 有没有人有一些改进的想法?
Revised question 修改后的问题
Seemingly, I was unable to state my question completely clear and unambiguous. 看来,我无法完全清楚,明确地陈述我的问题。 It turned out, that what I actually wanted was something slightly different.
原来,我真正想要的是稍有不同的东西。
Assume, that I have two sorted std::vector<double>
containers s1
and s2
. 假设我有两个排序的
std::vector<double>
容器s1
和s2
。 I wanted to create a new sorted container s
containing all values in s1
and some values in s2
, whereas are value v
from s2
is only contained in s
if and only if there is no value u
in s1
, such that std::fabs(uv)<1e-6
. 我想创建一个新的排序后的容器
s
其中包含s1
中的所有值和s2
某些值,而且仅当s1
没有u
时,才将s2
中的值v
包含在s
中,例如std::fabs(uv)<1e-6
。
Hence, I only want the values of s2
to be in the resulting container s
, if there are not too close to some values in s1
. 因此,如果
s1
值不太接近某些值,我只希望s2
的值位于结果容器s
中。
I'm very sorry for not stating my question so clear beforehand and I'm really delighted about the feedback I already got so far. 非常抱歉,我事先没有这么清楚地陈述我的问题,对于到目前为止已经得到的反馈,我感到非常高兴。 Maybe there are still ideas I can get from here?
也许我仍然可以从这里得到一些想法?
The vectors are sorted. 向量已排序。 The result is to be a sorted vector as well.
结果也将是排序的向量。
Using std::merge()
is a good start, but your example falls short of optimal performance in two ways: 使用
std::merge()
是一个好的开始,但是您的示例在两种方面达不到最佳性能:
The first is trivially addressed: 首先简单地解决:
ret.reserve(std::max(sorted1.size(), sorted2.size()));
The second can be solved by changing the output iterator given to std::merge()
. 第二个可以通过更改给
std::merge()
的输出迭代器来解决。 Instead of std::back_inserter(ret)
, create your own unique_inserter(ret)
, like this: 代替
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;
}
};
This is like std::back_inserter
but does nothing if a new value is equivalent to the last one. 就像
std::back_inserter
但是如果新值等于最后一个值, std::back_inserter
执行任何操作。 This way, unwanted values are never inserted, and do not need to be erased later. 这样,就永远不会插入不需要的值,并且以后不需要擦除它们。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.