【问题标题】:Iterator for all combinations of 2 ranges2个范围的所有组合的迭代器
【发布时间】:2021-09-24 04:23:36
【问题描述】:

是否可以使用 boost::iterators 库来创建显示 2 个范围的组合结果的迭代器?请注意,为了使用,我们需要输出是迭代器。我们也不希望首先手动创建所有组合的向量。 (注:我们用 C++17 编译)

一个人为的例子:

auto v = std::vector<int>({1,2,3});
auto s = std::set<double>({0.5, 1.5});
auto range = combineElements(v.begin(), v.end(), s.begin(), s.end(), [](int i, double d){ return std::pair{i, d}; });
for (auto [i, d] : range)
   std::cout << std::to_string(i) << ',' <<std::to_string(d) << ";";
// Expected output: 1,0.5;1,1.5;2,0.5;2,1.5;3,0.5;3,1.5;

我查看了boost::iterators的文档,发现:

  • Zip:这将第一个范围的第 n 个元素与第二个范围的第 n 个元素组合在一起。但是,不会将第 n 个元素与第 m 个元素组合。
  • 生成器:需要提供的生成器可以进行手动记账,保留 6 个迭代器:两个范围的开始、结束和当前。但是,它没有办法阻止它。
  • 函数输入:与生成器类似,我们可以将这些迭代器置于状态中,并使用结束迭代器为结束迭代器创建结束状态。但是,状态并没有提供给生成器来计算迭代器的值。
  • 排列:适用于单个范围
  • 变换:在单个范围内工作

我是否正确地得出结论,在这种情况下,唯一的选择是手动编写客户迭代器?

【问题讨论】:

  • range-v3cartesian_product 视图。 Demo
  • 感谢您的标签,不幸的是,我没有那个库可供我使用。但是,它可能值得研究。
  • 通过快速搜索,我没有在 boost 中找到 cartesian_product(除了 hana,它似乎在这里不适用)。

标签: c++ boost c++17 cartesian-product boost-iterators


【解决方案1】:

我是否正确地得出结论,在这种情况下,唯一的选择是手动编写客户迭代器?

几乎是的。您可能希望将其分解为一个迭代器适配器,该适配器将每个元素重复 N 次,另一个将整个范围重复 M 次,这样您就可以zip 这对。

template <class Iterator>
class repeat_iterator
  : public boost::iterator::iterator_adaptor< repeat_iterator<Iterator>, Iterator > 
{
  typedef boost::iterator::iterator_adaptor< repeat_iterator<Iterator>, Iterator > super_t;
  friend class boost::iterator::iterator_core_access;
  size_t len = 1;
  size_t curr = 0;

public:
  repeat_iterator() {}

  explicit repeat_iterator(Iterator x, size_t len, curr = 0)
      : super_t(x), len(len), curr(curr) {}

private:
  void increment() { 
      if (++curr == len) { 
          curr = 0;
          ++base_reference(); 
      }
  }
  void decrement() {
      if (curr-- == 0) {
          curr = len - 1;
          --base_reference(); 
      } 
  }
  void advance(typename super_t::difference_type n)
  {
      n += curr;
      base_reference() += n / len;
      curr = n % len;
  }
  template <class OtherIterator>
  typename super_t::difference_type
  distance_to(unstride_iterator<OtherIterator> const& y) const
  {
      return ((base() - y.base()) * len) + (curr - y.curr);
  }
};

template <class Iterator>
class cycle_iterator
  : public boost::iterator::iterator_adaptor< cycle_iterator<Iterator>, Iterator > 
{
  typedef boost::iterator::iterator_adaptor< cycle_iterator<Iterator>, Iterator > super_t;
  friend class boost::iterator::iterator_core_access;
  Iterator first;
  Iterator last;

public:
  cycle_iterator() {}

  explicit cycle_iterator(Iterator first, Iterator last)
      : super_t(first), first(first), last(last) {}

private:
  void increment() { 
      if (++base_reference() == last) { 
          base_reference() = first; 
      }
  }
  void decrement() {
      if (base_reference() == first) {
          base_reference() = last - 1; 
      } 
  }
  void advance(typename super_t::difference_type n)
  {
      n += std::distance(first, base_reference());
      n %= std::distance(first, last);
      base_reference() = first + n;
  }
};

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-11-26
    • 1970-01-01
    • 2014-09-08
    • 2017-06-07
    • 2013-07-08
    • 1970-01-01
    • 1970-01-01
    • 2013-05-14
    相关资源
    最近更新 更多