我有两个数组。典型的是int和bool。 bool数组指示元素是否已被删除。 现在我想要一个返回迭代器的函数,迭代器只迭代未删除的元素。重要的是该函数不应分配新内存(例如在新向量中复制元素)。有没有办法用标准STL做到这一点?
std::array<int,5> element={ 1 , 2 , 4 , 8 , 10 };
std::array<bool,5> deleted={ true, true, false, false, true };
std::vector<int>::iterator getNotDeleted(){
...
}
示例:
deleted= { true, true, false, false, true };
element= { 1 , 2 , 4 , 8 , 10 };
getNotDeleted should return a std::vector<int>::iterator that Iterates over
{4,8}
答案 0 :(得分:3)
你可以为此编写一个迭代器,只需构造一个知道两个向量的迭代器,它就是两个向量中的当前位置。然后,在推进迭代器时,跳过任何标记为已删除的元素。
template<class T>
struct maybe_deleted_iterator {
typedef int difference_type;
typedef T value_type;
typedef T& reference;
typedef T* pointer;
typedef std::forward_iterator_tag iterator_category;
maybe_deleted_iterator();
maybe_deleted_iterator(std::vector<T>& e, std::vector<bool>& d, bool is_beginning);
maybe_deleted_iterator& operator++();
reference operator*() const;
pointer operator->() const;
bool operator==(const maybe_deleted_iterator& rhs);
bool operator!=(const maybe_deleted_iterator& rhs);
private:
std::vector<T>* elements;
std::vector<bool>* deleted;
typename std::vector<T>::iterator e_iter;
std::vector<bool>::iterator d_iter;
};
然后,简单地迭代!
int main() {
std::vector<int> element = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
std::vector<bool> deleted = {1, 0, 0, 1, 1, 0, 1, 0, 1, 1};
maybe_deleted_iterator<int> it(element, deleted, true);
maybe_deleted_iterator<int> end(element, deleted, false);
for(; it!=end; ++it) {
std::cout << *it << ' ';
}
}
LeSnip3R建议让成员成为开始/结束对,以便它可以在任何两个容器上工作,但我认为这对学习更容易理解。在实际代码中,我希望看到它完成而不提及像vector
这样的特定容器。
答案 1 :(得分:1)
你可以像这样滚动自己:
#include <array>
#include <iostream>
#include <functional>
template <class T>
struct no_op : std::unary_function <T,bool>
{
bool operator() (const T& x) const
{
return x;
}
};
template <class ItSource,
class ItPredicate,
class PredMod = no_op<bool> >
class ConditionalIterator
{
ItSource _srcBegin;
ItSource _srcEnd;
ItPredicate _predBegin;
ItPredicate _predEnd;
void MoveNext()
{
while (_predBegin != _predEnd &&
_srcBegin != _srcEnd &&
PredMod()(!*_predBegin))
{
++_predBegin;
++_srcBegin;
}
}
public:
typedef ConditionalIterator & Reference;
typedef typename std::iterator_traits<ItSource>::value_type ValueType;
ConditionalIterator(ItSource srcBegin, ItSource srcEnd,
ItPredicate predBegin, ItPredicate predEnd)
: _srcBegin(srcBegin)
, _srcEnd(srcEnd)
, _predBegin(predBegin)
, _predEnd(predEnd)
{
MoveNext();
}
ConditionalIterator(ConditionalIterator const &other)
: _srcBegin(other._srcBegin)
, _srcEnd(other._srcEnd)
, _predBegin(other._predBegin)
, _predEnd(other._predEnd)
{
}
ConditionalIterator &operator=(ConditionalIterator const &other)
{
if (this != &other)
{
_srcBegin = other._srcBegin;
_srcEnd = other._srcEnd;
_predBegin = other._predBegin;
_predEnd = other._predEnd;
}
return (*this);
}
Reference operator++()
{
++_predBegin;
++_srcBegin;
MoveNext();
return (*this);
}
ConditionalIterator operator++(int)
{
ConditionalIterator cit = *this;
operator++();
return (cit);
}
operator bool() const
{
return (_srcBegin != _srcEnd &&
_predBegin != _predEnd);
}
ValueType operator*()
{
return (*_srcBegin);
}
};
template <class PredMod, class ItSource, class ItPred>
ConditionalIterator<ItSource, ItPred, PredMod> MakeConditionalIterator(ItSource srcBegin, ItSource srcEnd,
ItPred predBegin, ItPred predEnd)
{
return (ConditionalIterator<ItSource, ItPred, PredMod>(srcBegin, srcEnd, predBegin, predEnd));
}
这段代码远非完整,但应该让您入门。 然后就像这样使用它:
int main()
{
std::array<int,5> element={ 1 , 2 , 4 , 8 , 10 };
std::array<bool,5> deleted={ false, true, false, false, true };
auto cit_valid = MakeConditionalIterator<std::logical_not<bool> >(element.begin(), element.end(),
deleted.begin(), deleted.end());
auto cit_delete = MakeConditionalIterator<no_op<bool> >(element.begin(), element.end(),
deleted.begin(), deleted.end());
while (cit_delete)
{
std::cout << *cit_delete++ << std::endl;
}
while (cit_valid)
{
std::cout << *cit_valid++ << std::endl;
}
return (0);
}
答案 2 :(得分:0)
因此,正如Mooing Duck在评论中所示,可以在数组的任意元素上定义迭代器。 我的立场得到了纠正,但我仍然建议你考虑一些不那么繁琐的解决方案;你可以(而这些只是我想到的两个解决方案,还有更多):
std::vector
或std::list
之类的容器并实际擦除数组中的元素,因此您可以使用普通迭代器对其进行迭代(此变体:复制原始数组的元素)在std::vector
上可以执行删除,保持原始矢量安全)