【发布时间】:2012-11-09 09:06:28
【问题描述】:
我需要删除 C++ STL 向量中的双重条目。重要的一点是结果向量中元素的顺序必须与输入向量中的顺序相同。是否有一种算法(例如在 stl、boost 中)可以做到这一点?
【问题讨论】:
-
std::unique要求所有重复条目都按连续顺序排列。这是我无法实现的假设。
我需要删除 C++ STL 向量中的双重条目。重要的一点是结果向量中元素的顺序必须与输入向量中的顺序相同。是否有一种算法(例如在 stl、boost 中)可以做到这一点?
【问题讨论】:
std::unique 要求所有重复条目都按连续顺序排列。这是我无法实现的假设。
这里有两种可能的情况:向量已经排序或者没有。
如果是,std::erase 和 std::unique 可以轻松解决此问题,如其他答案所示。
如果不是,那么您可以实现目标
v.erase(std::remove_if(v.begin(), v.end(), predicate), v.end());
但是有一个问题,predicate 的指定并非易事:它是一个接受一个参数(要考虑的值)的函数,它需要回答“向量中是否有任何相等的值?”这个问题。 .由于没有告诉您提供的参数在向量中的确切位置,这意味着您必须保持相当多的手动状态才能回答这个问题。
这里一个方便的选择是使用std::set 来完成一些繁重的工作:
std::set<decltype(v)::value_type> set(v.begin(), v.end());
v.erase(
std::remove_if(
v.begin(),
v.end(),
[&set] (decltype(v)::value_type item) { return !set.erase(item); }),
v.end());
它的作用是使用向量中的值预填充std::set,然后通过查看是否已从集合中删除一个项目来检查它是否以前见过。这样,结果将仅保留输入中比较相等的每组项目中的第一项。
【讨论】:
如果你的向量没有排序,因此你不能只使用std::unique(同样不能排序会破坏你的订单),你可以使用类似这个函数的东西(使用 C++11 lambdas):
template<typename FwdIt> FwdIt unordered_unique(FwdIt first, FwdIt last)
{
typedef typename std::iterator_traits<FwdIt>::value_type value_type;
std::set<value_type> unique;
return std::remove_if(first, last, [&unique](const value_type &arg) {
return !unique.insert(arg).second; });
}
可以使用通常的 erase-romve-idiom 调用:
v.erase(unordered_unique(v.begin(), v.end()), v.end());
当然,您也可以使用 C++11 的 std::unordered_set 而不是 std::set(当然对于可散列类型)来避免平均情况下的 O(n log n)。
【讨论】:
std::unique怎么样?
auto firstDup = std::unique(myvector.begin(), myvector.end());
【讨论】:
使用下一个:vec.erase( unique( vec.begin(), vec.end() ), vec.end() );
【讨论】: