带有STL的两个数组上的条件迭代器

时间:2013-05-13 21:37:17

标签: c++ stl iterator

我有两个数组。典型的是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}

3 个答案:

答案 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 << ' ';
    }
}

http://coliru.stacked-crooked.com/view?id=40e4d1a54f71643ee9f885f82d71fb46-50d9cfc8a1d350e7409e81e87c2653ba

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在评论中所示,可以在数组的任意元素上定义迭代器。 我的立场得到了纠正,但我仍然建议你考虑一些不那么繁琐的解决方案;你可以(而这些只是我想到的两个解决方案,还有更多):

  • 对数组进行排序,保留前面的有效条目,并仅从第一个元素到第n个有效元素进行迭代
  • 使用诸如std::vectorstd::list之类的容器并实际擦除数组中的元素,因此您可以使用普通迭代器对其进行迭代(此变体:复制原始数组的元素)在std::vector上可以执行删除,保持原始矢量安全)