如何迭代特定范围的 std::set/std::multiset?

时间:2021-03-03 07:59:54

标签: c++ stl associative-array

对于像 std::set<std::string> set={ "aaa", "bbb", "ccc", "ddd", "eee", "fff" }; 这样的 std::set 如何在不跟踪额外索引的情况下迭代此集合的特定范围 [a, b]?

像这样:

for(auto it = set.begin(); it!=set.begin()+b; ++it)
   std::cout << *it << " ";

或者像这样:

for(auto it = set.begin()+a; it!=set.begin()+b; ++it)
   std::cout << *it << " ";

其中 a<=bb<=set.size()

2 个答案:

答案 0 :(得分:3)

你不能做set.begin()+a,但你可以做std::advance(it, a)

#include <iostream>
#include <set>
#include <string>
 
int main()
{
    std::set<std::string> set={ "aaa", "bbb", "ccc", "ddd", "eee", "fff" };
    size_t a = 1, b = 4;
    auto it = set.begin(), it_end = set.begin();
    std::advance(it, a);
    std::advance(it_end, b);
    for(; it!= it_end; ++it)
        std::cout << *it << " ";
}

不幸的是,您不能执行 auto it = std::advance(set.begin(), a); 之类的操作,因为 advance 通过引用获取迭代器并对其进行了更改。

https://ideone.com/8nRjgr

更好的解决方案使用 std::next,感谢@Evg:

#include <iostream>
#include <set>
#include <string>
 
int main()
{
    std::set<std::string> set={ "aaa", "bbb", "ccc", "ddd", "eee", "fff" };
    size_t a = 1, b = 4;
    for(auto it = std::next(set.begin(), a), it_end = std::next(it, b-a); it != it_end; ++it)
        std::cout << *it << " ";
}

https://ideone.com/6wgpMZ

答案 1 :(得分:1)

您可以编写自己的 slice 类,有点像 std::span

#include <cstdio>
#include <set>
#include <string>

template <class Iter>
class slice {
 private:
  Iter _beg;
  Iter _end;

 public:
  slice(Iter beg, Iter end) noexcept 
    : _beg{beg}
    , _end{end} 
  {}

  slice(Iter beg, std::size_t sz) noexcept 
    : slice(beg, std::next(beg, sz)) 
  {}

  auto begin() const noexcept { return _beg; }
  auto end() const noexcept { return _end; }
};

int main() {
  std::set<std::string> const set{"aaa", "bbb", "ccc", "ddd", "eee", "fff"};

  slice const sl(set.begin(), 3);

  for (auto const& elm : sl) std::puts(elm.c_str());
}

Godbolt