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

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

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

感谢您的建议。

4

4 回答 4

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());
于 2012-11-02T08:34:05.557 回答
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?

所以我认为,除非您更准确地定义您的问题,否则您实际上不可能编写代码或我们来帮助您。

您可能想查看不相交集数据结构。取决于您正在尝试做什么,这可能是解决此问题的最有效方法。

于 2012-11-02T08:14:51.543 回答
0

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

于 2012-11-02T08:14:05.950 回答
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 的第三个模板参数来指示引用而不是依赖推导)。请注意,谓词 operator() 是非常量的。

于 2012-11-02T08:31:11.947 回答