什么是获取std :: list的前N个元素或整个列表(如果N> =列表大小)的正确且安全的方法(并将N = 0作为一种处理方式)?
更新:
实际上,我不一定需要一个新列表,我只想在后续代码中操作列表的子集。我假设创建一个新列表是这样做的合理方式(请注意,列表大小通常不超过50)。
更新:
实际上,我不一定需要一个新列表,我只想在后续代码中操作列表的子集。我假设创建一个新列表是这样做的合理方式(请注意,列表大小通常不超过50)。
std::list<int> a;
size_t n = 13;
auto end = std::next(a.begin(), std::min(n, a.size()));
创建一个新的列表,其中包含第一个列表的前n个元素:
std::list<int> b(a.begin(), end);
或者填充现有列表:
std::list<int> b;
std::copy(a.begin(), end, std::back_inserter(b));
std::advance
会处理越过末尾的情况。至少标准只是将其视为迭代器前进,没有提及检查这种情况。 - chrisa.begin() + n
呢? - David Gstd::next
无论如何都可以工作。 - chrisb
可能更有意义。 - juanchopanzaoperator+
替换掉能够正常工作的 std::next
,导致你的代码出现了问题? - Benjamin Lindleytemplate<typename T>
std::list<T> first_n(const std::list<T> &in, std::size_t n) {
return std::list<T> out{in.begin(),
std::next(in.begin(), std::min(in.size(), n))};
}
// list<int> input;
list<int> output;
for (list<int>::const_iterator i = input.begin(); i != input.end() && N > 0; ++i, --N)
output.push_back(*i);
std::next
来找到用于初始化第二个列表的末尾迭代器。对于像std::vector
或std::deque
这样的容器来说,这是一个便宜的操作,因为它们有随机访问迭代器。但是对于std::list
,由于它具有双向迭代器,需要迭代遍历每个项直到N。然后当您初始化第二个列表时,需要再次迭代。 - Benjamin Lindley在你的问题中提到了以下内容:
实际上,我并不一定需要一个新列表,我只想在后续代码中操作列表的子集
从C++17开始,可以使用std::for_each_n
。
例如,让我们计算列表中前N(4)个数字的平方。
示例1:就地修改:
std::list<int> nums{ 1,2,3,4,5,6,7,8 };
//MAKE NOTE OF SENDING ARGUMENT AS A REFERENCE (int& num)
std::for_each_n(nums.begin(), 4, [](int& num) { num = num * num; });
//PRINT
for (auto n : nums)
std::cout << n << " ";
示例2:修改并将它们放入不同的列表中:
std::list<int> nums2{ 1,2,3,4,5,6,7,8 };
std::list<int> newNums;
//MAKE NOTE OF CAPTURE [&}, newNums EXPOSED INSIDE LAMBDA.
std::for_each_n(nums2.begin(), 4, [&](int num) {newNums.push_back(num * num); });
//PRINT
for (auto n : newNums)
std::cout << n << " ";
std::for_each_n(std::execution::par,nums.begin(), 4, [](int& num) { num = num * num; });
std::list
来处理输入或结果。在大多数情况下,使用std::vector
会使生活变得更加简单。大多数算法都适用于定义范围,这将允许你在正确的子集上操作而无需进行任何复制。 - Jerry Coffinstd::nth_element
来获取它们。 - Jerry Coffin