web-dev-qa-db-ja.com

ソートされたベクトル内の重複したアイテムを削除する方法

私は現在_vector<int> c_を含む_{1,2,2,4,5,5,6}_を含み、cが_{1,4,6}_を持つように重複した数を削除したいです。インターネット上の多くのソリューションが重複の1つを削除するだけでなく、重複した数のすべての出現箇所を削除しようとしています。

cを常にソートします。

私は現在持っています

_#include <iostream>
#include <vector>

int main() {
  vector<int> c{1,2,2,4,5,5,6};
  for (int i = 0; i < c.size()-1; i++) {
    for (int j=1; j<c.size();j++){
      if(c[i] == c[j]){
         // delete i and j? 
      }
    }
  }
}
_

現在の要素と次の要素を比較できるように、2つのループを使用しようとしました。これが私の疑問が蹴ったところです。私が問題に正しく近づいているかどうかはかなりありません。

私の問題に取り組む方法についての助けを得ることができますか?

9
WhitneyD

std::unique/std::copy_ifと同様に、次のことができます。

void keep_unique(std::vector<int>& v){
    auto it = v.begin();
    auto w = v.begin();
    while (it != v.end())
    {
        auto next = std::find_if(it, v.end(), [&](int e){ return e != *it; });
        if (std::distance(it, next) == 1) {
            if (w != it) {
                *w = std::move(*it);
            }
            ++w;
        }
        it = next;
    }
    v.erase(w, v.end());
}

デモ

2
Jarod42

逆に繰り返します ベクトル内の最後の要素を消去するだけなので、消去時にO(N)の操作を引き起こさずに要素シフトを発生させません。。また、他のデータ構造を割り当てる必要はありません。

発生したすべての要素について、隣接する要素が等しいかどうかを確認し、そうであれば、その要素のすべてのインスタンスを削除します。

ベクトルをソートするか、少なくとも重複によってグループ化される必要があります。

#include <iostream>
#include <vector> 
int main()
{
    std::vector<int> c {1, 2, 2, 4, 5, 5, 6};
    
    for (int i = c.size() - 1; i > 0;) 
    {
        const int n = c[i];
        if (c[i - 1] == n)
        {
            while (c[i] == n)
            {
                c.erase(c.begin() + i--);
            }
        }
        else
        {
            i--;
        }

    }

    //output result
    for (auto it : c)
    {
        std::cout<<it;
    }
    std::cout << std::endl;
}
 _

Output: 146
 _

アップデート

実際のO(N) "Sentinel値を使用した実装:

#include <iostream>
#include <vector> 
#include <limits>
#include <algorithm>

int main()
{
    std::vector<int> c { 1, 2, 2, 4, 5, 5, 6 };
    const int sentinel = std::numeric_limits<int>::lowest(); //assumed that no valid member uses this value.
    for (int i = 0; i < c.size() - 1;) 
    {
        const int n = c[i];
        if (c[i + 1] == n)
        {
            while (c[i] == n)
            {
                c[i++] = sentinel;
            }
        }
        else
        {
            i++;
        }
    }
    
    c.erase(std::remove(c.begin(),c.end(),sentinel), c.end());

    for (auto it : c) std::cout<< it << ' ';
}
        
 _
1
Rotem

一般に、それらを繰り返しながらコンテナから削除するときには非常に注意しなければなりません。 C++ STLは、ネストされたループを使用するよりも簡単かつより速く(平均的に)行うことができます。

_#include <vector> 
#include <algorithm>
#include <unordered_set>

int main() {
    std::vector<int> c{1,2,2,4,5,5,6};
    std::unordered_multiset<int> unique( c.begin(), c.end() );
    c.erase(std::remove_if(c.begin(),c.end(),[&](const auto& e){return unique.count(e)>1;}),c.end());

    for(auto e: c){
        std::cout<<e<<' ';
    }
}

//Output: 1 4 6
_

あるいは、_std::map<int,std::size_t>_を使用してこのように発生することをカウントすることもできます。

1
Quimby

これは、実行時エラーを回避するためにイテレータを適切に使用することで達成できます。

次のコードを見てください。

#include <iostream>
#include <vector>

int main() {
    
    std::vector<int> c{1,2,2,4,5,5,6};

    for (auto it = c.begin(); it != c.end(); ){
        
        auto it2 = it;
        advance(it2, 1);
        
        bool isDuplicate = false;
        
        for(; it2 != c.end(); ++it2){
            if(*it == *it2){
                c.erase(it2);
                isDuplicate = true;
            }
        }
        
        if(isDuplicate){
            auto it3 = it;
            advance(it3, 1);
            c.erase(it);
            it = it3;
        }else{
            it++;
        }
    }
    
    for (auto it = c.begin(); it != c.end(); it++){
        
        std::cout<<*it<<" ";
    }
}
 _

出力:

1 4 6 
 _

使用する std :: remove_if 後部に複数回発生するアイテムを移動してから消去します。

#include <iostream>
#include <vector>
#include <algorithm>


int main()
{

    std::vector<int> V {1,2,2,4,5,5,6};

    auto it = std::remove_if(V.begin(), V.end(), [&](const auto& val) 
    { 
        return std::count(V.begin(), V.end(), val) > 1;
    });

    V.erase(it, V.end());

    for (const auto& val : V)
        std::cout << val << std::endl;
    
    return 0;
}
 _

出力:

1
4
6
 _

デモ用: https://godbolt.org/z/j6fxe1

0
Tony Tannous