[英]How to remove almost duplicates from a vector in C++
我有一個浮點數的std :: vector我想不包含重復項,但是填充向量的數學運算不是100%精確的。 向量的值相差幾百,但應視為相同的點。 例如,這里有一些值:
...
X: -43.094505
X: -43.094501
X: -43.094498
...
從這樣的向量中刪除重復項的最佳/最有效方法是什么。
首先使用std::sort
矢量進行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
排序始終是良好的第一步。 使用std::sort()
。
刪除不夠獨特的元素: std::unique()
。
最后一步,調用resize()
,也可以shrink_to_fit()
。
如果要保留訂單,請在副本上執行前3個步驟(但省略收縮)。
然后使用帶有lambda的std::remove_if
,檢查副本中是否存在元素(二進制搜索)(如果找到則不要忘記將其刪除),並且只保留復制中找到的元素。
我說std::sort()
它,然后逐個遍歷它並刪除一定范圍內的值。
您可以在同一個向量上有一個單獨的寫迭代器,在最后有一個調整大小操作 - 而不是為每個被刪除的元素調用erase()
或者為了提高性能和更小的內存使用而使用另一個目標副本。
如果向量不能包含重復項,則使用std :: set可能更合適。 然后,您可以使用自定義比較對象將小更改視為無關緊要。
我會做以下事情:
創建一個set<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作為謂詞
到目前為止,大多數答案的問題在於你有一個不同尋常的“平等”。 如果A和B相似但不相同,則要將它們視為相等。 基本上,A和A + epsilon仍然相等,但A + 2 * epsilon沒有(對於某些未指定的epsilon)。 或者,根據您的算法,A *(1 + epsilon)和A *(1 + 2 * epsilon)不會。
這確實意味着A + epsilon比較等於A + 2 * epsilon。 因此,A = B和B = C並不意味着A = C.這打破了<algorithm>
常見假設。
您仍然可以對值進行排序,這是一個理智的事情。 但是你必須考慮如何處理結果中的大量類似值。 如果范圍足夠長,則第一個和最后一個之間的差異仍然很大。 沒有簡單的答案。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.