用于包含不同元素的 2 个向量的单个迭代器 (c++)
Single iterator for 2 vectors holding different elements (c++)
我有两个相同长度的向量。其中之一包含 double 向量:
std::vector<std::vector<double>> A;
第二个持有双打
std::vector<double> B;
我所说的“相同长度”是指 A 包含的双精度向量与 B 包含的双精度向量一样多。
我想同时用一个迭代器遍历它们。我觉得我需要创建一个 class 来做到这一点。像
std::vector<vector<double>>::iterator iter = A.begin();
for (A= iter.begin(); iter != A.end(); iter++)
{
(*iter).A // I access an element of A std::vector<double>
(*iter).B // I access an element of B (double)
}
我检查了一个类似的问题,这个问题非常接近我想做的:
但在我的例子中,迭代器有两种不同的类型,分别是std::vector<vector<double>>::iterator
和vector<double>::iterator
,所以这个问题的解决方案不起作用,但我想它很接近。
我该怎么做?什么是最好的方法?
原则上,您可以编写一个自定义迭代器,它有一个 first
和一个 second
,分别引用 A
和 B
的元素。然而,自定义迭代器并不简单。更简单的替代方法是使用基于循环的普通旧索引:
for (size_t i = 0; i < A.size() && i < B.size(); ++i)
{
A[i]; // I access an element of A std::vector<double>
B[i]; // I access an element of B (double)
}
或者使用两个迭代器
auto itA = A.begin();
auto itB = B.begin();
for ( ; itA != A.end() && itB != B.end(); ++itA,++itB) {
//...
}
您可能还对来自 boost 的 zip_iterator
或来自 ranges-v3 库的 view::zip
感兴趣:
#include <iostream>
#include <vector>
#include <range/v3/view.hpp>
int main() {
std::vector<int> A{1,2,3,4,5};
std::vector<double> B{1.2,3.4,5.6,7.8,9.1};
for (const auto& [a, b] : ranges::view::zip(A, B)) {
std::cout << a << " " << b << "\n";
}
}
标准范围库基于 Nieblers 范围,但到目前为止 zip
还没有进入标准库。如果我理解正确的话,这是 C++23 的预期。
PS:请注意,您的 for (A= iter.begin(); iter != A.end(); iter++)
可以被认为是“老式的”。由于 C++11 有 range based for loops,它允许您从开始到结束迭代容器的元素。他们更进一步,还向您隐藏了迭代器(它们仍然存在),以减少打字错误的机会。虽然,就像基于迭代器的循环比基于索引的循环稍微不灵活一样,基于范围的循环比基于迭代器的循环更不灵活。他们只让你从 begin
迭代到 end
:
for (const auto& a : A) {
a; // a is a const reference to element in A
}
为了完整起见,我只是提到这一点,与旧的基于迭代器的循环相比,基于范围的循环将两个迭代器“压缩”为一个既不简单也不复杂。
我有两个相同长度的向量。其中之一包含 double 向量:
std::vector<std::vector<double>> A;
第二个持有双打
std::vector<double> B;
我所说的“相同长度”是指 A 包含的双精度向量与 B 包含的双精度向量一样多。 我想同时用一个迭代器遍历它们。我觉得我需要创建一个 class 来做到这一点。像
std::vector<vector<double>>::iterator iter = A.begin();
for (A= iter.begin(); iter != A.end(); iter++)
{
(*iter).A // I access an element of A std::vector<double>
(*iter).B // I access an element of B (double)
}
我检查了一个类似的问题,这个问题非常接近我想做的:std::vector<vector<double>>::iterator
和vector<double>::iterator
,所以这个问题的解决方案不起作用,但我想它很接近。
我该怎么做?什么是最好的方法?
原则上,您可以编写一个自定义迭代器,它有一个 first
和一个 second
,分别引用 A
和 B
的元素。然而,自定义迭代器并不简单。更简单的替代方法是使用基于循环的普通旧索引:
for (size_t i = 0; i < A.size() && i < B.size(); ++i)
{
A[i]; // I access an element of A std::vector<double>
B[i]; // I access an element of B (double)
}
或者使用两个迭代器
auto itA = A.begin();
auto itB = B.begin();
for ( ; itA != A.end() && itB != B.end(); ++itA,++itB) {
//...
}
您可能还对来自 boost 的 zip_iterator
或来自 ranges-v3 库的 view::zip
感兴趣:
#include <iostream>
#include <vector>
#include <range/v3/view.hpp>
int main() {
std::vector<int> A{1,2,3,4,5};
std::vector<double> B{1.2,3.4,5.6,7.8,9.1};
for (const auto& [a, b] : ranges::view::zip(A, B)) {
std::cout << a << " " << b << "\n";
}
}
标准范围库基于 Nieblers 范围,但到目前为止 zip
还没有进入标准库。如果我理解正确的话,这是 C++23 的预期。
PS:请注意,您的 for (A= iter.begin(); iter != A.end(); iter++)
可以被认为是“老式的”。由于 C++11 有 range based for loops,它允许您从开始到结束迭代容器的元素。他们更进一步,还向您隐藏了迭代器(它们仍然存在),以减少打字错误的机会。虽然,就像基于迭代器的循环比基于索引的循环稍微不灵活一样,基于范围的循环比基于迭代器的循环更不灵活。他们只让你从 begin
迭代到 end
:
for (const auto& a : A) {
a; // a is a const reference to element in A
}
为了完整起见,我只是提到这一点,与旧的基于迭代器的循环相比,基于范围的循环将两个迭代器“压缩”为一个既不简单也不复杂。