iterator for 2d vector

前端 未结 8 980
眼角桃花
眼角桃花 2020-12-04 10:32

How to create iterator/s for 2d vector (a vector of vectors)?

8条回答
  •  攒了一身酷
    2020-12-04 11:00

    Another way to interpret this question is that you want a 1D iterator over a vector> for example to feed it to for_each() or some other algorithm.

    You can do that like this:

    #include 
    
    #include 
    #include 
    #include 
    
    // An iterator over a vector of vectors.
    template
    class vv_iterator : public std::iterator{
    public:
    
      static vv_iterator begin(std::vector>& vv) {
        return vv_iterator(&vv, 0, 0);
      }
      static vv_iterator end(std::vector>& vv) {
        return vv_iterator(&vv, vv.size(), 0);
      }
    
      vv_iterator() = default;
      // ++prefix operator
      vv_iterator& operator++()
      {
        // If we haven't reached the end of this sub-vector.
        if (idxInner + 1 < (*vv)[idxOuter].size())
        {
          // Go to the next element.
          ++idxInner;
        }
        else
        {
          // Otherwise skip to the next sub-vector, and keep skipping over empty
          // ones until we reach a non-empty one or the end.
          do
          {
            ++idxOuter;
          } while (idxOuter < (*vv).size() && (*vv)[idxOuter].empty());
    
          // Go to the start of this vector.
          idxInner = 0;
        }
        return *this;
      }
      // --prefix operator
      vv_iterator& operator--()
      {
        // If we haven't reached the start of this sub-vector.
        if (idxInner > 0)
        {
          // Go to the previous element.
          --idxInner;
        }
        else
        {
          // Otherwise skip to the previous sub-vector, and keep skipping over empty
          // ones until we reach a non-empty one.
          do
          {
            --idxOuter;
          } while ((*vv)[idxOuter].empty());
    
          // Go to the end of this vector.
          idxInner = (*vv)[idxOuter].size() - 1;
        }
        return *this;
      }
      // postfix++ operator
      vv_iterator operator++(int)
      {
        T retval = *this;
        ++(*this);
        return retval;
      }
      // postfix-- operator
      vv_iterator operator--(int)
      {
        T retval = *this;
        --(*this);
        return retval;
      }
      bool operator==(const vv_iterator& other) const
      {
        return other.vv == vv && other.idxOuter == idxOuter && other.idxInner == idxInner;
      }
      bool operator!=(const vv_iterator &other) const
      {
        return !(*this == other);
      }
      const T& operator*() const
      {
        return *this;
      }
      T& operator*()
      {
        return (*vv)[idxOuter][idxInner];
      }
      const T& operator->() const
      {
        return *this;
      }
      T& operator->()
      {
        return *this;
      }
    
    private:
      vv_iterator(std::vector>* _vv,
                  std::size_t _idxOuter,
                  std::size_t _idxInner)
        : vv(_vv), idxOuter(_idxOuter), idxInner(_idxInner) {}
    
      std::vector>* vv = nullptr;
      std::size_t idxOuter = 0;
      std::size_t idxInner = 0;
    };
    
    
    
    int main()
    {
        std::vector> a = {{3, 5, 2, 6}, {-1, -4, -3, -5}, {100}, {-100}};
        std::reverse(vv_iterator::begin(a), vv_iterator::end(a));
        for (const auto& v : a)
        {
            std::cout << "{ ";
            for (auto i : v)
               std::cout << i << " ";
            std::cout << "}\n";
        }
    }
    

    Prints:

    { -100 100 -5 -3 }
    { -4 -1 6 2 }
    { 5 }
    { 3 }
    

    Note this won't work with std::sort() because that requires a random access iterator. You could make it a random access iterator but you'd have to scan the vector at the start so you can map from flat index to idxOuter and idxInner in constant time. Not totally trivial but not hard either.

提交回复
热议问题