首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在容器上的循环中同时访问更多元素的STL方法

在容器上的循环中同时访问更多元素的STL方法
EN

Stack Overflow用户
提问于 2014-09-03 09:12:59
回答 4查看 3.4K关注 0票数 31

是否可以重写这个原始循环:

代码语言:javascript
复制
vector<double> v { ... };
for (size_t i = 1; i<v.size(); ++i) {
  v[i]*=v[i-1];
}

或者更神秘的:

代码语言:javascript
复制
for (auto i = v.begin()+1; i<v.end(); ++i) {
  (*i) *= *(i-1);
}

(类似地,也可能访问vi-2,.)以一种更STLish的方式?

是否有其他形式比上面的相同或更好(无论在风格和表演)?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2014-09-03 09:19:44

我能想象到的最STLish的方式:

代码语言:javascript
复制
std::partial_sum(std::begin(v), std::end(v),
                 std::begin(v), std::multiplies<double>());

示例:

代码语言:javascript
复制
#include <iostream>
#include <vector>
#include <iterator>
#include <numeric>
#include <functional>

int main()
{
    std::vector<double> v{ 1.0, 2.0, 3.0, 4.0 };

    std::partial_sum(std::begin(v), std::end(v),
                     std::begin(v), std::multiplies<double>());

    std::copy(std::begin(v), std::end(v),
                             std::ostream_iterator<double>(std::cout, " "));
}

输出:

代码语言:javascript
复制
1 2 6 24 

现场演示链接。

票数 40
EN

Stack Overflow用户

发布于 2014-09-03 09:20:03

您可以使用std::transform来完成这一任务,即需要两个输入序列的重载:

代码语言:javascript
复制
int container[] = {1,2,3};
std::transform(
    std::begin(container), std::end(container) - 1,
    std::begin(container) + 1, std::begin(container) + 1,
    [](auto a, auto b) { return a * b; }
    );

但是手工编码的循环更加可读性更强。

票数 10
EN

Stack Overflow用户

发布于 2014-09-03 18:20:22

如果您想要一种通用的方法来执行滑动窗口,而不是一种无法传输的STL-ish方法来解决您的特定问题,那么您可以考虑以下荒谬的胡说八道:

代码语言:javascript
复制
#include <array>
#include <cstddef>
#include <memory>
#include <tuple>

namespace detail {
  template<std::size_t, typename>
  class slide_iterator;
}
template<std::size_t N, typename I>
detail::slide_iterator<N, I> slide_begin(const I&);
template<std::size_t N, typename I>
detail::slide_iterator<N, I> slide_end(const I&);

namespace detail {

template<std::size_t N, typename T, typename... Args>
struct repeat {
  typedef typename repeat<N - 1, T, T, Args...>::type type;
  template<typename I>
  type operator()(const I& it, Args&... args) const {
    auto jt = it;
    return repeat<N - 1, T, T, Args...>()(++jt, args..., *it);
  }
};
template<typename T, typename... Args>
struct repeat<0, T, Args...> {
  typedef std::tuple<Args&...> type;
  template<typename I>
  type operator()(const I&, Args&... args) const {
    return type(args...);
  }
};

template<std::size_t N, typename I /* forward iterator */>
class slide_iterator {
public:

  typedef slide_iterator iterator;
  typedef decltype(*I{}) reference;
  typedef typename repeat<N, reference>::type window_tuple;

  slide_iterator() = default;
  ~slide_iterator() = default;
  slide_iterator(const iterator& it) = default;
  iterator& operator=(const iterator& it) = default;

  window_tuple operator*() const {
    return repeat<N, reference>()(first_);
  }

  iterator& operator++() { // prefix
    ++first_;
    ++last_;
    return *this;
  }

  iterator operator++(int) { // postfix
    auto tmp{*this};
    operator++();
    return tmp;
  }

  friend void swap(iterator& lhs, iterator& rhs) {
    swap(lhs.first_, rhs.first_);
    swap(lhs.last_, rhs.last_);
    swap(lhs.dirty_, rhs.dirty_);
    swap(lhs.window_, rhs.window_);
  }

  friend bool operator==(const iterator& lhs, const iterator& rhs) {
    return lhs.last_ == rhs.last_;
  }

  friend bool operator!=(const iterator& lhs, const iterator& rhs) {
    return !operator==(lhs, rhs);
  }

  friend iterator slide_begin<N, I>(const I& it);
  friend iterator slide_end<N, I>(const I& it);

private:

  I first_;
  I last_; // for equality only

};

template<typename T, std::size_t N>
struct slide_helper {
  T& t;
  auto begin() -> decltype(slide_begin<N>(t.begin())) {
    return slide_begin<N>(t.begin());
  }
  auto end() -> decltype(slide_end<N>(t.end())) {
    return slide_end<N>(t.end());
  }
};

} // ::detail

// note it is undefined to call slide_begin<N>() on an iterator which cannot
// be incremented at least N - 1 times
template<std::size_t N, typename I>
detail::slide_iterator<N, I> slide_begin(const I& it) {
  detail::slide_iterator<N, I> r;
  r.first_ = r.last_ = it;
  std::advance(r.last_, N - 1);
  return r;
}

template<std::size_t N, typename I>
detail::slide_iterator<N, I> slide_end(const I& it) {
  detail::slide_iterator<N, I> r;
  r.last_ = it;
  return r;
}

template<std::size_t N, typename T>
detail::slide_helper<T, N> slide(T& t) {
  return {t};
}

示例用法:

代码语言:javascript
复制
#include <iostream>
#include <vector>

int main() {
  std::vector<int> v{1, 2, 3, 4};
  /* helper for
     for (auto it = slide_begin<2>(v.begin()),
               et = slide_end<2>(v.end()); it != et ... BLAH BLAH BLAH */
  for (const auto& t : slide<2>(v)) {
    std::get<1>(t) *= std::get<0>(t);
  }
  for (const auto& i : v) {
    std::cout << i << std::endl;
  }
}
票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25640469

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档