发现和擦除重复和擦除值在另一矢量

问题描述:

我具有形式std::vector<int> astd::vector<double> b的两个向量,例如发现和擦除重复和擦除值在另一矢量

a= 1,2,3,3,4,5,6; 
b=0.1, 0.3, 0.2, 0.5, 0.6, 0.1, -0.2; 

两个矢量具有相同的尺寸的和实际上他们的工作像XY对((1,0.1) , (2,0.3)...etc)。在MATLAB我

a= 1,2,3,4,5,6; 
b=0.1, 0.3, 0.5, 0.6, 0.1, -0.2; 

:幸运的是,a从少排序,以更始终

我想找到的第一个向量的副本,然后删除他们的第一个,在我的例子输出应该是会做这样的事情:

b(find(diff(a) == 0)) = []; 
a(find(diff(a) == 0)) = []; 

我知道我能做到这一点使用循环和if语句的老式方法,但我相信有更优雅的方式来做到这一点在C++与容器和迭代器。搜索互联网有很多例子可以清除第一个向量中的重复内容,但不能使用相同的索引来清除第二个向量中的元素。

任何帮助表示赞赏。

+6

而不是有平行的向量为什么没有一个向量存储在一个单一的元素的两部分数据?然后,做你想做的事情就变得微不足道了。 – NathanOliver

+5

或者最初将数据填充到'std :: map '中,并且由于地图不支持重复键,因此您不需要擦除重复项 –

+0

您真的在'int'向量中存储'0.3'吗? – Galik

我不认为有办法解决使用循环和if语句。

iterator j = b.begin(); 
    iterator ahead = a.begin(); 
    ahead++; 
    while(1) { 
     if(ahead* == behind*) { // If we have a duplicate 
      a.erase(ahead);  // we need to erase the entry in a 
      b.erase(j);   // and the entry in b 
     } 
     else {     // Otherwise, just move on 
      j++; 
      ahead++; 
      behind++; 
     } 
     if(ahead == a.end()) // Once we reach the end of the vectors, end the loop 
      break; 
    } 

这可能会奏效。我不完全知道erase()是如何工作的,但我认为逻辑应该起作用。

的原因,你会发现很少(如果有的话)的本写得很好的例子是,大多数人都喜欢通过定义是这样开始:

struct coord { 
    int x; 
    double y; 

    // Since we want X values unique, that's what we compare by:  
    bool operator==(coord const &other) const { 
     return x == other.x; 
    } 
}; 

利用这一点,我们可以得到独特的X和对应的Y对,没有任何明确的循环很容易地,因为标准库中已经提供了用于特定目的的算法:

std::vector<coord> ab; 
// populate ab here ... 

// ensure only unique X values, removing the corresponding Y when we remove an X 
ab.erase(std::unique(ab.begin(), ab.end()), ab.end()); 

如果你真的需要保持ab作为单独的数组,我可能会仍然做些什么相当类似,但使用zip iterator来创建看起来/行为足够相似的东西,你仍然可以使用uniqueerase来完成这项工作。

必须有一个更简单的方法呢?

// compare the index vector by using the 
// values of another vector 
struct compare_by_other 
{ 
    std::vector<int>& v; 

    compare_by_other(std::vector<int>& v): v(v) {} 

    bool operator()(std::size_t idx1, std::size_t idx2) const 
     { return v[idx1] == v[idx2]; } 
}; 

std::vector<int> a = {1 , 2 , 3 , 3 , 3 , 4 , 4 , 5 }; 
std::vector<double> b = {0.2, 0.5, 0.1, 0.9, 2.5, 9.6, 0.3, 2.4}; 

// create an index to track which indexes need to be removed 
std::vector<std::size_t> indexes(a.size()); 
std::iota(std::begin(indexes), std::end(indexes), 0); 

// remove all the indexes that the corresponding vector finds duplicated 
auto end = std::unique(std::begin(indexes), std::end(indexes), compare_by_other(a)); 

// erase all those elements whose indexes do not appear in the unique 
// portions of the indexes vector 

a.erase(std::remove_if(std::begin(a), std::end(a), [&](auto& n){ 
    return std::find(std::begin(indexes), end, std::distance(a.data(), &n)) == end; 
}), std::end(a)); 

// same for b 

b.erase(std::remove_if(std::begin(b), std::end(b), [&](auto& n){ 
    return std::find(std::begin(indexes), end, std::distance(b.data(), &n)) == end; 
}), std::end(b)); 

不幸的是,我不知道在香草C++中这样做的优雅方式。

如果你愿意使用一个库,埃里克Neibler的Range-V3(目前的道路上为标准),可以在一个半愉快的方式做到这一点:

#include <range/v3/all.hpp> 
#include <iostream> 

namespace rng = ranges::v3; 

int main() 
{ 
    std::vector<int> a{1, 2, 3, 3, 4, 5, 6}; 
    std::vector<double> b{0.1, 0.3, 0.2, 0.5, 0.6, 0.1, -0.2}; 

    auto view = rng::view::zip(a, b); 

    auto result = rng::unique(view, [](auto&& x, auto&& y) { 
     return x.first == y.first; 
    }); 

    // This is a bit of a hack... 
    const auto new_end_idx = rng::distance(rng::begin(view), result); 

    a.erase(a.begin() + new_end_idx, a.end()); 
    b.erase(b.begin() + new_end_idx, b.end()); 

    std::cout << rng::view::all(a) << '\n'; 
    std::cout << rng::view::all(b) << '\n'; 
} 

输出:

[1,2,3,4,5,6] 
[0.1,0.3,0.2,0.6,0.1,-0.2] 

Wandbox link

它仍然不是很理想(因为它无法获取原始迭代器回了view::zip迭代器作为据我所知),但它不是太糟糕。

无码全部A建议制定:

简单,低效率的方式:

  1. 使用zip iterator对待两个向量作为二元组/对的单个范围。 (它不一定是Boost的,但标准库没有一个AFAICR)。现在你已经减少了用自定义比较标准过滤出模糊的问题(假设你不介意输出不是两个不同的数组)
  2. 使用此构造函数构建一组二元组:

    template< class InputIt > 
    set(InputIt first, InputIt last, 
        const Compare& comp = Compare(), 
        const Allocator& alloc = Allocator()); 
    

    在你的情况下,默认分配是好的,但要比较设置成类似

    [](const std::tuple<int, double>& lhs, 
        const std::tuple<int, double>& rhs) -> bool 
    { 
         return std::get<0>(lhs) < std::get<0>(rhs); 
    } 
    

    ,或者你可以写一个适当的功能他们做同样的事情。这取决于你的zip迭代器是否暴露了元组或std :: pair当然。

就是这样!

更有效的做法是构建一个元组向量,但在压缩的迭代器范围上使用std::copy_if进行填充。