2

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

3 回答 3

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.

于 2013-05-13T22:24:19.067 回答
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);
}
于 2013-05-13T22:23:59.047 回答
0

因此,正如 Mooing Duck 在评论中显示的那样,您可以在数组的任意元素上定义迭代器。我的立场是正确的,但我仍然建议您考虑不那么繁琐的解决方案;你也可以(这些只是我想到的两个解决方案,还有更多):

  • 对数组进行排序,将有效条目保持在前面,并仅从第一个元素迭代到第 n 个有效元素
  • 使用容器,例如std::vectororstd::list并实际擦除数组中的元素,因此您可以使用普通迭代器对它们进行迭代(此变体:将原始数组的元素复制到std::vector可以执行删除的元素中,保留原始向量安全的)
于 2013-05-13T21:57:30.027 回答