4

値が特定の間隔内にあるベクトル (または別の stl コンテナー) からアイテムを削除する便利な方法はありますか?

たとえば、浮動小数点値を持つベクトルを取得しました

1.1 1.3 2.2 3.2 4.1 5.2 5.1 1.1 8.0 2.1

および 0.2 のデルタ。これにより、次の結果が得られます。

1.1 2.2 3.2 4.1 5.1 8.0

したがって、デルタ内のすべての「重複」項目を削除し、範囲内の値の 1 つを保持します。値が「クラスター化」されており、これらの差が 3*delta を超えていると見なすことができます。クラスターの 1 つの値 (平均値) のみを保持し、クラスターから他のすべての値を削除する必要があります。

確かに、ネストされたループで反復することは可能ですが、反復子が変化するため、これは非常に複雑に思えます。そのため、より便利な方法を考えました。たとえば remove_if を見つけましたが、この関数は「比較」できません。

提案をありがとう。

4

4 に答える 4

7

std::unique述語で使用できます。

template <typename It, typename Predicate>
It unique(It first, It last, Predicate pred);

の最もよく使用される形式はstd::unique、述語を使用せず、シーケンスから重複を削除するだけです。ただし、フィルターを実装するものを作成することはできます (この場合、ギャップを使用して 2 つの値を比較します)。何かのようなもの:

bool CompareWithGap(double a, double b)
{
  return abs(a - b) <= 0.2;
}

そしてそれを使って呼び出すstd::unique

auto it = std::unique(v.begin(), v.end(), CompareWithGap);

vベクトル (またはその他のシーケンス) はどこにありますか。

編集: を使用する前にシーケンスをソートする必要があることを忘れていましたstd::unique。これができない場合は、独自のアルゴリズムを作成する必要があります。

2番目の編集:クリスチャン・ラウがコメントで指摘したように、完了するために、eraseメソッドを使用してシーケンスから削除されたアイテムを消去できるようになりました:

v.erase(it, v.end());
于 2012-11-02T08:34:05.557 に答える
6

「範囲内の値の1つ」が明確に定義されていないため、質問は実際には非常に複雑です。たとえば、与えられた

1.1 1.2 1.3

あなたはどちらを飼いたいですか?おそらく最初のもの、つまり1.1です。さて、どうですか

0.9 1.1 1.3

最初の 1 つのルールに従って、0.9 と 1.3 を保持しますが、代わりに 1.1 だけを保持することもできます。問題は、0.9 と 1.3 が「重複」しているかどうかです。あなたはこれを十分に定義しているとは思いません。

この場合、1.1 1.2 1.3 1.4 1.5 1.6 はどうでしょうか? すべての値が 1 つの他の値の 0.2 以内にありますが、すべてが他のすべての値の 0.2 以内にあるわけではありません。それで、それらはすべて重複していますか?それとも分割する必要がありますか?もしそうなら、それらはどのように分割されるべきでしょうか? おそらく 1.1 と 1.4 を選びますか?

したがって、問題をもう少し正確に定義しない限り、コードを記述したり、私たちがあなたを支援したりすることは実際には不可能だと思います.

互いに素な集合のデータ構造を見たいと思うかもしれません。何をしようとしているのかによっては、この問題を解決する最も効率的な方法かもしれません。

于 2012-11-02T08:14:51.543 に答える
0

最初の項目を保持したい場合 (つまり、0.9、1.1、および 1.3 がある場合は、0.9 および 1.3 を保持します)、述語はクラスにする必要があります。

理想的には、クラスは次のようになります。

class IsWithinRange
{
   std::set< double > values;
   double tolerance;

public:
   explicit IsWithinRange( double tol ) : tolerance( tol )
   {
   }

   bool operator()( double val )
   {
       std::set< double >::iterator iter = values.lower_bound( val );
       if( iter != values.end() )
       {
           if( *iter - val < tolerance )
           {
              return false;
           }
       }
       if( iter != values.begin() )
       {
          --iter;
          if( val - *iter < tolerance )
          {
              return false;
          }
       }
       values.insert( val );
       return true;
    }
};

これはファンクター述語クラスとして機能するはずですstd::remove_ifが、内部 std::set を必要以上にコピーする可能性があるため、必要に応じて「最適化」を試みることができます。(セットを使用して作成しますが、これはかなり煩わしく、remove_if の 3 番目のテンプレート パラメーターを指定して、推定に頼るのではなく参照を示すこともできます)。述語 operator() は const ではないことに注意してください。

于 2012-11-02T08:31:11.947 に答える
0

既存のベクトルを反復し、必要なデータを入力しながら、新しいベクトルを作成できますか? その後、古いベクターを削除して、新しいベクターへの参照を返すことができます。

于 2012-11-02T08:14:05.950 に答える