代码之家  ›  专栏  ›  技术社区  ›  Sandeep Datta

如何使用线性索引在多维数组中设置值

  •  1
  • Sandeep Datta  · 技术社区  · 16 年前

    使用线性索引在多维数组中设置值的最有效方法是什么?例如,给定一个数组…

    int[,,] arr2 = {   {{0,1,2}, {3,4,5}, {6,7,8}}
                    , {{9,10,11}, {12,13,14}, {15,16,17}}
                    , {{18,19,20}, {21,22,23}, {24,25,26}}
            };
    

    如何使用线性索引将所有元素设置为30…

    //This code does not work
    for (int i = 0; i < arr.Length; i++)
    {
        arr.SetValue(30, i);
    }
    

    显然,上面的setValue()不适用于多维数组。

    这是我能想到的最好的解决办法…

    编辑:在代码中添加了一些说明…

    static class Program
    {
        static void Main(string[] args)
        {
            //Sample input. 
            int[,,] arr2 = {   {{0,1,2}, {3,4,5}, {6,7,8}}
                            , {{9,10,11}, {12,13,14}, {15,16,17}}
                            , {{18,19,20}, {21,22,23}, {24,25,26}}
                    };
    
            int[] arr1 = { 1, 2, 3, 4 };
    
            setElementsTo30(arr2);
            setElementsTo30(arr1);
    
        }
    
        //Must be able to process int arrays of arbitrary dimensions and content
        private static void setElementsTo30(Array arr)
        {
            IList<int> cumulativeLength = getCumulativeLengths(arr);
    
            for (int i = 0; i < arr.Length; i++)
            {
                SetValue(arr, i, 30, cumulativeLength);
            }
        }
    
        public static void SetValue(this Array arr, int index, object value, IList<int> cumulativeLength)
        {
            int[] arrayIndex = new int[arr.Rank];
    
            for (int dim = arr.Rank-1; dim >= 0; dim--)
            {
                arrayIndex[dim] = index / cumulativeLength[dim] % arr.GetLength(dim);
            }
    
            arr.SetValue(value, arrayIndex);
        }
    
        private static IList<int> getCumulativeLengths(Array arr)
        {
            List<int> lengths = new List<int>(arr.Rank);
    
            for (int dim = 0; dim < arr.Rank; dim++)
            {
                int prod = 1;
                for (int i = dim + 1; i < arr.Rank; i++)
                {
                    prod *= arr.GetLength(i);
                }
                lengths.Add(prod);
            }
    
            return (IList<int>)lengths;
        }
    }
    

    有没有一种方法可以更有效地做到这一点,并可能使用框架本身提供的某些功能(即可以轻松使用的功能)。

    谢谢,
    SDX2000。

    4 回复  |  直到 7 年前
        1
  •  2
  •   Jimmy    16 年前

    你为什么需要伊利斯特?

    static void SetValue2(this Array a, object value, int i) {
        int[] indices = new int[a.Rank];
        for (int d = a.Rank - 1; d >= 0; d--) {
            var l = a.GetLength(d);
            indices[d] = i % l;
            i /= l
        }
        a.SetValue(value, indices);
    }
    

    测试代码:

    static void Main(string[] args) {
        int[, ,] arr2 = {   
            {{0,1,2}, {3,4,5}, {6,7,8}}, 
            {{9,10,11}, {12,13,14}, {15,16,17}}, 
            {{18,19,20}, {21,22,23}, {24,25,26}}
        };
        for (int i = 0; i < arr2.Length; i++) {
            arr2.SetValue2(30, i);
        }
    }
    
        2
  •  1
  •   JB King    16 年前

    你知道最初会有多少个元组吗?如果你说的是一个尺寸为a x b x c x d的矩阵,你不能用下面的方法得到所有索引的列表吗?

    for i=0 to (a*b*c*d)
    
           Array[i % a, (i/a) % b, (i/(a*b) % c, i / (a*b*c)] = 30
    

    这样,当计数器滚动到不同的边界上时,每个后续索引都会增加。如果还有更多的值,那么就可以推广到n个元组,只需将前面的值相乘即可。如果想以不同的方式进行遍历,可以反转索引的算术运算。

        3
  •  0
  •   Jay Bazuzi Buck Hodges    16 年前

    SetValue() 应该工作。看一看 this 为了更多的灵感。

    编辑:你不能就这么做吗?

    {{30,30,30}, {30,30,30}, {30,30,30}}
     , {{30,30,30}, {30,30,30}, {30,30,30}}
      , {{30,30,30}, {30,30,30}, {30,30,30}
    
    }
    

    作为旁注,您确定要返回 IList<int> getCumulativeLengths ?

    我一直在想,输入要大方,输出要严格。

        4
  •  0
  •   Makeman    7 年前
        public static void CopyToMultidimensionalArray(this IList<object> source, Array target, IList<int> dimensions)
        {
            var indices = new int[dimensions.Count];
            for (var i = 0; i < source.Count; i++)
            {
                var t = i;
                for (var j = indices.Length - 1; j >= 0; j--)
                {
                    indices[j] = t % dimensions[j];
                    t /= dimensions[j];
                }
    
                target.SetValue(source[i], indices);
            }
        }