Swift算法使用多重索引枚举多线性映射:[Int]

时间:2018-05-17 08:29:52

标签: arrays swift algorithm

多线性映射M的元素存储在长度为N的一维数组中,其中由S:[Int] = [p,q,r,...]定义的形状S为q*p*r*... = N。 Shape的大小可变,在编译时不知道。

我试图解决的问题是使用整数数组访问地图元素的一般方法,其中单个值是Shape S中的坐标,例如:M[1,3,2], M[2,3,3,3]等...这是一个问题不同于地图元素的简单枚举。

一种方法是使用M[i,j,k]并实现下标方法。不幸的是,这种方法硬编码了地图的形状,并且算法不再是通用的。

假设有一个实用程序函数,它从派生自地图的Shape的元组返回一个元素索引,以便:

func index(_ indexes:[Int]) -> Int {....}

func elementAt(indexes:[Int]) -> Element { 
   return elements_of_the_map[self.index(indexes)]
}

M.elementAt(indexes:[i,j,k]) or M.elementAt(indexes:[i,j,k,l,m])始终有效。所以此时的问题是构建数组[i,j,k,...]

问题:是否有算法有效枚举这些索引?嵌套循环不起作用,因为在编译时不知道循环的数量,并且递归函数似乎增加了很多复杂性(特别是跟踪以前的索引)。

我正在考虑算法'a la'base-x计数,即向右上方索引添加一个单位,如果计数超过地图形状的元素数,则向左移动一个单位。

2 个答案:

答案 0 :(得分:1)

这里是代码,它是原始的,但应该有效。我的想法是从右到左递增,从形状约束[2,3,3]中[1,2,1]移动说到[1,2,2]。

func add_one_unit(shape:[Int],indexes:[Int]) -> [Int]? {
    //Addition is right to left, so we have to reverse the arrays. Shape Arrays are usually very small, so it's fast.
    let uu = Array(indexes.reversed()); //Array to add one index to.
    let shape_reversed = Array(shape.dimensions.reversed()); //Shape array.

    var vv:[Int] = [];
    var move_next:Bool = true;

    for i in 0..<uu.count {
        if move_next {
            if uu[i] < shape_reversed[i] - 1 { //Shape constraint is OK.
                vv.append(uu[i] + 1)
                move_next = false;
            } else {
                vv.append(0) //Shape constraint is reached.
                move_next = true;//we'll flip the next index.
            }
        } else {
            vv.append(uu[i]) //Nothing to change.
        }
    }
    return ( vv.reduce(true, { $0&&($1 == 0) }) ) ? nil : Array(vv.reversed()); //Returns nil once we reached the Zero Vector.
}

哪个给出了

add_one_unit(shape:[2,3,3],indexes:[0,0,0]) -> [0,0,1]
add_one_unit(shape:[2,3,3],indexes:[1,2,2]) -> [0,0,0]/nil

完成此操作后,此函数可用于枚举任何形状的多线性映射([i,j,k,...]到唯一索引的映射,例如矩阵到索引映射是必要的,并且取决于在你的实现上),或从任何特定的向量切片地图。

答案 1 :(得分:1)

同样的想法,但代码较少:

func addOneUnit(shape: [Int], indexes: [Int]) -> [Int]? {
    var next = indexes
    for i in shape.indices.reversed() {
        next[i] += 1
        if next[i] < shape[i] {
            return next 
        }
        next[i] = 0
    }
    return nil
}