c ++从值在区间内的向量中删除项目

时间:2012-11-02 08:10:43

标签: c++ stl containers

是否有方便的方法从值(在某个时间间隔内)的向量(或其他stl容器)中删除项目?

例如:我得到了一个带浮点值的向量

1.1 1.3 2.2 3.2 4.1 5.2 5.1 1.1 8.0 2.1

和delta为0.2,这将导致以下结果

1.1 2.2 3.2 4.1 5.1 8.0

因此删除增量内的所有“重复”项目并保留该范围内的一个值。 可以假设这些值是“聚集的”,其中这些值之间的差异大于3 * delta。只应保留群集的一个值(平均值),应删除群集中的所有其他值。

当然,可以使用嵌套循环进行迭代,但这看起来很复杂,因为迭代器的变化,所以我想到了一种更方便的方法。我找到了remove_if,但是这个函数不能“比较”。

感谢您的建议。

4 个答案:

答案 0 :(得分:7)

您可以将std::unique与谓词一起使用:

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

最常用的std::unique形式不带谓词,只删除序列中的重复项。但是你可以编写一个实现你的过滤器(在你的情况下,使用间隙比较两个值)并设置。类似的东西:

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之前对序列进行排序。如果这不是一个选项,你必须编写自己的算法。

第二次编辑:完成后,正如Christian Rau在评论中指出的那样,您现在可以使用erase方法删除序列中删除的项目:

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

答案 1 :(得分:6)

你的问题实际上非常复杂,因为“范围内的一个值”没有明确定义。比如给出

1.1 1.2 1.3

你要保留哪个?大概是第一个,即1.1。好了,现在怎么样

0.9 1.1 1.3

遵循第一条规则,我们保持0.9和1.3,但我们可以只保留1.1。我认为的问题是0.9和1.3'重复'还是没有?我认为你已经很好地定义了这个。

这种情况怎么样,1.1 1.2 1.3 1.4 1.5 1.6?所有值都在另一个值的0.2之内,但并非所有值都在每个其他值的0.2之内。那么它们都是重复的吗?或者你需要拆分它们吗?如果是这样,他们应该如何分开,或许选择1.1和1.4?

所以我想在你更准确地定义问题之前,你不可能编写代码或帮助我们。

您可能需要查看disjoint-set data structure。根据您正在尝试做的事情,它可能是解决此问题的最有效方法。

答案 2 :(得分:0)

您可以在迭代现有向量并填充所需数据的同时创建新向量吗?然后,您可以删除旧向量并返回对新向量的引用。

答案 3 :(得分: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的。