如何迭代n维数组?

11

如何在给定每个维度的大小和维度数量的情况下迭代n维数组?

int n;
int size[n];

由于维数不固定,我不能为每个维度编写嵌套循环。我需要代码适用于每个维数。

此外,实际数据是存储在n维数组中还是包含所有数据的平坦数组中都没有关系。两者都可以接受。

int data[16][42][14];   // n-dimensional array
int data[16 * 42 * 14]; // flat array containing the same data

你想用这些n维度做什么?我猜你需要知道这个,因此你也知道了维度的数量... - Veger
维度数量不确定?这似乎很棘手,因为您需要知道维度的数量才能知道下面每个维度的大小。我没有尝试过,但我猜您可以编写一些可怕的递归代码来解决这个问题... - Mats Petersson
维度的数量不同,但每个维度的大小已知。 - danijar
“iterate over the array” 是什么意思?是查看每个元素吗?还是查看每个带有索引的元素?或者像amit的回答一样,只是迭代所有索引向量?如果是第一个选项,您可以通过首先计算size[]数组的乘积来迭代平面数组。 - rici
5个回答

8

您可以使用递归,为每个维度“猜测”其索引并在较小的问题上递归调用,类似于以下伪代码:

iterate(d,n,size,res):
   if (d >= n): //stop clause
       print res
       return
   for each i from 0 to size[d]:
       res.append(i) //append the "guess" for this dimension
       iterate(d+1,n,size,res)
       res.removeLast //clean up environment before next iteration

其中:

  • d 是当前访问的维度
  • sizen 是输入
  • res 是表示当前部分结果的向量

使用 iterate(0,n,size,res) 调用,其中 res 初始化为空列表。


C++ 代码应该是这样的:

void iterate(int d,int n,int size[], int res[]) {
    if (d >= n) { //stop clause
       print(res,n);
       return;
   }
   for (int i = 0; i < size[d]; i++) { 
       res[d] = i;
       iterate(d+1,n,size,res);
   }
}

完整的代码和一个简单的例子可以在ideone上找到。


伟大的伪代码。我很感兴趣看看你如何翻译大小[n]的平面数组 - 我本来想建议这样做,但懒得将平面数组转换为多维数组。 - Mats Petersson
使用C++,您可以使用模板在编译时(而不是运行时)进行递归。然而,这要求您现在就知道维度的数量。 - muksie

5

Python代码:

def nd_range(start, stop, dims):
  if not dims:
    yield ()
    return
  for outer in nd_range(start, stop, dims - 1):
    for inner in range(start, stop):
      yield outer + (inner,)

例子:

print(list(nd_range(0, 3, 3)))

[(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 0), (0, 1, 1), (0, 1, 2), (0, 2, 0), (0, 2, 1), (0, 2, 2), (1, 0, 0), (1, 0, 1), (1, 0, 2), (1, 1, 0), (1, 1, 1), (1, 1, 2), (1, 2, 0), (1, 2, 1), (1, 2, 2), (2, 0, 0), (2, 0, 1), (2, 0, 2), (2, 1, 0), (2, 1, 1), (2, 1, 2), (2, 2, 0), (2, 2, 1), (2, 2, 2)]

1

在 JavaScript 中,不使用递归列出所有组合:

function listCoords(dimensions) {
    var cumulatives = new Array(dimensions.length);
    var total = 1;
    for (var d = dimensions.length - 1; d >= 0; d--) {
        cumulatives[d] = total;
        total *= dimensions[d];
    }
    var coords = new Array(total);
    for (var i = 0; i < total; i++) {
        var coord = new Array(dimensions.length);
        for (var d = dimensions.length - 1; d >= 0; d--) {
            coord[d] = Math.floor(i / cumulatives[d]) % dimensions[d];
        }
        coords[i] = coord;
    }
    return coords;
}

例子:

  • [2, 3] 返回 [[0,0],[0,1],[0,2],[1,0],[1,1],[1,2]]
  • [3, 2] 返回 [[0,0],[0,1],[1,0],[1,1],[2,0],[2,1]]
  • [2, 2, 2] 返回 [[0,0,0],[0,0,1],[0,1,0],[0,1,1],[1,0,0],[1,0,1],[1,1,0],[1,1,1]]

1

您可以使用递归。以下是嵌套数组的伪代码解决方案:

iterate_n(array, n)
    if n == 0
        do something with the element
    else
        for ary in array
            iterate_n(ary, n-1)
        end_for
    end_if
end

0

以下是我在MATLAB中使用递归完成的方法:

function out=iterate(data,func,dim)
% Usage: out=iterate(data,func)
% This function individually applies the user defined function 'func' to 
% every element of the array 'data'.
% The third input 'dim' is for internal recursive use only, after global 
% setup variables have been initialized.


global sz inds g_out
% 'sz' is size(data) with singleton dimensions removed
% 'inds' is an array of size [1 length(sz)] containing the current indices
% 'g_out' is where parts of the output are accumulated throughout iteration

if nargin<3
    %Setup 'inds' 'sz' 'g_out'
    dim=1;  %'dim' is the current dimension to iterate through
    sz=size(data);
    if sz(2)==1
        sz=sz(1);
    end
    inds=ones(1,length(sz));

    %Initialize the output as the proper class
    %Depends on the output of the user given function
    switch class(func(data(1)))
        case 'logical'
            g_out= false(sz);
        case 'double'
            g_out=double(zeros(sz));
        case 'char'
            g_out=repmat(' ',sz);
        otherwise
            g_out=cast(zeros(sz),class(func(data(1)))); %#ok<ZEROLIKE>
    end
end

for i=1:sz(dim)
    inds(dim)=i;
    ndx=subs2ind(sz,inds);
    if dim<length(sz)
        iterate(data,func,dim+1);
    else
        g_out(ndx)=func(data(ndx));
    end
end
out=g_out;
end

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接