2017-06-01 108 views
0

我具有形式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

回答

0

我不認爲有辦法解決使用循環和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()是如何工作的,但我認爲邏輯應該起作用。

0

的原因,你會發現很少(如果有的話)的本寫得很好的例子是,大多數人都喜歡通過定義是這樣開始:

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來完成這項工作。

0

必須有一個更簡單的方法呢?

// 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)); 
0

不幸的是,我不知道在香草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迭代器作爲據我所知),但它不是太糟糕。

0

無碼全部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進行填充。