是否有一个类似STL的函数来用索引的某个函数填充数组

Is there an STL-like function to fill an array with some function of the index?

本文关键字:函数 索引 填充 数组 STL 有一个 是否      更新时间:2023-10-16

在C++中,我们有像std::fillstd::fill_n这样的函数,它们是用值填充指针数组、向量、std::array和其他容器的方便的单行方式。一些容器也有自己的fill方法,以允许使用恒定值填充。还有函数std::generate{_n}std::iota,前者允许使用生成器函数填充元素,后者用索引填充范围。

我正在寻找一个类似的解决方案——最好是一个在标准库中定义的单行解决方案——它允许用索引的一些函数填充容器。例如,这将是一个阵列的解决方案:

std::array<int, 100> arr;
for (std::size_t i = 0; i < 100; i++)
arr[i] = f(i);

其中CCD_ 7是索引的某个函数。

有没有一种综合的方法来做到这一点?

您可以使用有状态的lambda:

std::array<int, 100> arr;   
std::generate(arr.begin(), arr.end(), [i = std::size_t(0)]() mutable {return f(i++);});

但我认为这会使代码变得比需要的更复杂。使用纯循环可能是最好的选择。

我无法在编译器中尝试这一点,因为我找不到一个具有C++20范围的编译器,但一旦编译器实现了它们,类似的东西就会起作用:

std::ranges::transform(std::views::iota{1, arr.size()+1}, arr, f);

或者,如果你只想要生成的值的序列,只需要用创建一个范围

auto const values = std::views::iota{1, arr.size()+1} | std::views::transform(f);

在拥有C++20编译器之前,您可以使用其中一个范围库,例如在Boost或Eric Nieblers ranges-v3 中

考虑编写自己的STL类函数模板apply_idx_func()

template<typename FwdItor, typename F>
void apply_idx_func(FwdItor first, FwdItor last, F f) {
for (size_t idx = 0; first != last; ++first, ++idx)
*first = f(idx);
}

例如:

auto main() -> int {
std::array<int, 10> arr;
// just adds 100 to the index
auto func = [](size_t idx) -> int {
return 100 + idx;
};
apply_idx_func(std::begin(arr), std::end(arr), func);
for (auto elem: arr)
std::cout << elem << ' ';
std::cout << 'n';
}

输出为:

100 101 102 103 104 105 106 107 108 109

如果你总是遍历整个数组,你甚至不必使用任何stl函数,只需使用范围循环:

std::array<int, 100> arr;
int idx = 0;
for (auto& item : array)
item = f(idx++);

另一种选择是使用for_each(如果将来您想仅部分填充阵列,这可能更有用(

#include <algorithm>
std::array<int, 100> arr;
int idx = 0;
std::for_each(begin(arr), end(arr), [&idx](int &n){ n = f(idx++); });

不幸的是,在这两种情况下,您都必须有单独的索引变量(此处:idx(

#include <algorithm>
size_t i = 0;
std::generate_n(arr.begin(),arr.size(),[&i](){return f(i++);});

或者可能分两步:

#include <numeric>
std::iota(arr.begin(),arr.end(),0);
std::transform(arr.begin(),arr.end(),f);

在助推的帮助下,我们可以在一个步骤中做到这一点:

std::transform(
arr.begin(),
arr.end(),
boost::irange(0,arr.size()),
[](const auto& val,const auto& index){return f(index);}
);

https://www.boost.org/doc/libs/1_64_0/libs/range/doc/html/range/reference/ranges/irange.html