简体   繁体   English

使用不同的比较函数合并两个排序的双向量

[英]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>容器s1s2 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()是一个好的开始,但是您的示例在两种方面达不到最佳性能:

  1. You neglect to reserve capacity in the returned vector before the merge. 您忽略合并之前在返回的向量中保留容量。
  2. You insert all elements during the merge, then erase unwanted elements after it. 您在合并期间插入所有元素,然后在合并之后删除不需要的元素。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM