我有一个std :: vector的浮点数,我希望它不包含重复项,但是用于填充向量的数学并不完全精确。该向量具有相差几百分之几的值,但应视为同一点。例如,在其中一个中有一些值:
...
X: -43.094505
X: -43.094501
X: -43.094498
...
如何最好/最有效地从此类向量中删除重复项。
我有一个std :: vector的浮点数,我希望它不包含重复项,但是用于填充向量的数学并不完全精确。该向量具有相差几百分之几的值,但应视为同一点。例如,在其中一个中有一些值:
...
X: -43.094505
X: -43.094501
X: -43.094498
...
如何最好/最有效地从此类向量中删除重复项。
首先使用std::sort
对向量进行排序。然后使用自定义谓词的std::unique
函数来去除重复项。
std::unique(v.begin(), v.end(),
[](double l, double r) { return std::abs(l - r) < 0.01; });
// treats any numbers that differ by less than 0.01 as equal
vector::erase
,或者使用 unique_copy
写入到另一个容器中。多余的元素可以通过多种方式处理,包括我示例中展示的方法。这并不意味着这是解决此问题的唯一明确方法。 - Praetorian排序总是一个很好的第一步。使用 std::sort()
。
删除不足够唯一的元素:std::unique()
。
最后一步,调用 resize()
,也许还要调用 shrink_to_fit()
。
如果你想保留顺序,在副本上执行前面的三个步骤(省略缩小)。
然后使用带有lambda表达式的std::remove_if
,检查副本中元素的存在性(二进制搜索)(找到后别忘了删除),只保留在副本中找到的元素。
std::string
一样。我讨厌这种小小的不一致性。 - Deduplicatorreserve(0)
等同于调用shrink_to_fit()
,两者都是非绑定的收缩请求。对于vector
来说,reserve(...)
永远不是一个收缩请求。 - Deduplicatorset<double>
n * log(n)
,但它更简单,可以用几行代码完成。内存消耗将从仅存储向量的两倍。此外,每个元素的 set
消耗的内存略多于向量。但是,在使用后,您将销毁它。std::vector<double> v;
v.push_back(-43.094505);
v.push_back(-43.094501);
v.push_back(-43.094498);
v.push_back(-45.093435);
std::set<double> s;
std::vector<double>::const_iterator it = v.begin();
for(;it != v.end(); ++it)
s.insert(floor(*it));
v.swap(std::vector<double>());
v.resize(s.size());
std::copy(s.begin(), s.end(), v.begin());
嗨,你可以像这样比较
bool isAlmostEquals(const double &f1, const double &f2)
{
double allowedDif = xxxx;
return (abs(f1 - f2) <= allowedDif);
}
但这取决于您的比较范围,双精度不在您这一方面
如果您的向量已排序,则可以使用带有函数谓词的std::unique
我建议使用std::sort()
函数,然后逐一检查并删除在特定范围内的值。
你可以为同一个向量创建一个单独的写迭代器,并在最后进行一次resize操作,而不是为每个被删除的元素调用erase()
函数或者创建另一个目标副本以提高性能和减少内存使用。
set
。没有适用的偏序关系。特别地,如果a<b && b<c,则a<c,但是如果a<c,则a<=b || b<=c。在这种情况下,可以选择b=a+epsilon,c=a+2*epsilon。 - MSalters