我正在尝试遍历n维矩阵,其中矩阵的每个维也具有可变大小。
我特别想让每个元素具有多维坐标,就像for loop
给您i
来访问数组中的元素一样。
我想从根本上重新创建嵌套的for循环,如下面的代码,在该循环中,我可以将任何其他类型的数字放入dimensionSize
中。
std::vector<int> dimensionSize = {1, 4, 4};
for (int i = 0; i < dimensionSize [0]; i++)
{
for (int j = 0; j < dimensionSize [1]; j++)
{
for (int k = 0; k < dimensionSize [2]; k++)
{
std::cout << i << " " << j << " " << k << std::endl;
}
}
}
此嵌套循环的结果是...
0 0 0
0 0 1
0 0 2
0 0 3
0 1 0
0 1 1
0 1 2
0 1 3
0 2 0
0 2 1
0 2 2
0 2 3
0 3 0
0 3 1
0 3 2
0 3 3
到目前为止,我在C ++中遍历n维矩阵时发现的所有示例/解决方案都是非常凌乱的代码,并且对于固定维数例如9x9x9或3x3x3。
但是我的矩阵可能是1x256x513x3或各种大小。
我目前有以下功能,尽管有一个问题,但它接近我想要的功能。
void iterate_over_n_dimensions (std::vector<int>& counters,
std::vector<int> dimensionSizes,
int currentDimension)
{
for (long i = 0; i < dimensionSizes [currentDimension]; i++)
{
print_counter (counters);
if (currentDimension + 1 != dimensionSizes.size())
{
iterate_over_n_dimensions (counters,
dimensionSizes,
currentDimension + 1);
}
counters [currentDimension] ++;
counters [currentDimension] %= dimensionSizes [currentDimension];
}
}
运行以下内容...
int main(int argc, const char * argv[])
{
std::vector<int> dimensionSizes = {1, 4, 4};
std::vector<int> counters(dimensionSizes.size(), 0);
iterate_over_n_dimensions (counters, dimensionSizes, 0);
return 0;
}
此递归函数的结果是...
0 0 0
0 0 0
0 0 0
0 0 1
0 0 2
0 0 3
0 1 0
0 1 0
0 1 1
0 1 2
0 1 3
0 2 0
0 2 0
0 2 1
0 2 2
0 2 3
0 3 0
0 3 0
0 3 1
0 3 2
0 3 3
您可以看到,每次嵌套的for循环完成时,输出都会重复一次!重复在...
0 1 0
0 2 0
0 3 0
我添加的尺寸越多,这个问题就越严重。 例如,每次完成1x4x4x2矩阵的第4维循环时,都会重复此矩阵,而在其他地方则重复更多。
如果有人能提出一种与我当前函数一样简洁的解决方案,我将不胜感激!
现在,我将不得不实现一个带有大量for循环的大规模switch语句,并将维数的上限限制在5个左右。
答案 0 :(得分:4)
如果我理解正确,则希望迭代“ n维矩阵”的所有元素(实际上不称为“矩阵”),并且需要一种获取所有索引的方法。我将从这样的事情开始:
#include <iostream>
#include <vector>
struct multi_index {
std::vector<size_t> dimensions;
std::vector<size_t> current;
multi_index(std::vector<size_t> dim) : dimensions(dim), current(dim.size()) {}
void print() {
for (const auto& e : current) std::cout << e << " ";
std::cout << "\n";
}
bool increment() {
for (size_t i=0;i<dimensions.size();++i) {
current[i] += 1;
if (current[i] >= dimensions[i]) {
current[i] = 0;
} else {
return true;
}
}
return false;
}
};
int main() {
multi_index x{{1,2,3}};
do {
x.print();
} while (x.increment());
}
然后将其适应特定需求。例如,向量可能是std::array
,并且要依赖于实际的容器,您可能希望有一种简便的方法来访问容器中的元素而不必编写data[ x[0] ][ x[1] ][ x[2] ]
。
请注意,通常最好将数据展平为一维数据结构,然后仅映射索引。特别是当尺寸固定时,您可以从数据局部性中受益。上面的代码使您可以编写一个循环遍历所有维度的循环,然后需要反向映射,即将许多索引映射为平面索引。以下内容尚未经过全面测试,只是为了概述此想法:
#include <vector>
#include <utility>
template <typename T>
struct multi_dim_array {
std::vector<T> data;
std::vector<size_t> dimensions;
multi_dim_array(std::vector<size_t> dim) {
size_t total = 1;
for (const auto& d : dim) total *= d;
data.resize(total);
}
T& get(std::initializer_list<int> index) {
return data[flatten_index(index)];
}
size_t flatten_index(std::initializer_list<int> index) {
size_t flat = 0;
size_t sub_size = 1;
for (auto x = std::make_pair(0u,index.begin());
x.first < dimensions.size() && x.second != index.end();
++x.first, ++x.second) {
flat += (*x.second) * sub_size;
sub_size *= dimensions[x.first];
}
return flat;
}
};
int main(){
multi_dim_array<int> x{{2,2,3}};
x.get({1,1,1}) = 5;
}
将多维数据存储在平面数组/向量中后,编写一个简单的循环来迭代所有元素的操作就应该很简单。
PS:说实话,我没有费心在代码中发现问题,递归让我头晕:P
答案 1 :(得分:1)
我不确定我是否理解这个问题。如果您想一次访问多维数组的每个元素,则下面的代码应该可以完成此工作(在我的案例中,计数器计算每个元素被访问的次数,因此,最后应等于DimensionSizes):
void print_counter(std::vector<int>& counters)
{
for (unsigned int i = 0; i < counters.size(); ++i)
std::cout << counters[i] << " ";
std::cout << std::endl;
}
void iterate_over_n_dimensions(std::vector<int>& counters, std::vector<int> dimensionSizes, int currentDimension)
{
for (long i = 0; i < dimensionSizes[currentDimension]; i++)
{
counters[currentDimension] ++;
print_counter(counters);
}
if (currentDimension + 1 != dimensionSizes.size())
{
iterate_over_n_dimensions(counters,
dimensionSizes,
currentDimension + 1);
}
}
int main(int argc, const char * argv[])
{
std::vector<int> dimensionSizes = { 1, 4, 4 };
std::vector<int> counters(dimensionSizes.size(), 0);
iterate_over_n_dimensions(counters, dimensionSizes, 0);
return 0;
}
输出为:
1 0 0
1 1 0
1 2 0
1 3 0
1 4 0
1 4 1
1 4 2
1 4 3
1 4 4