遍历任意维数组遍历、数组

2023-09-11 03:53:42 作者:热血为霸i

使用C#,如何遍历一个多维数组的未知的尺寸?

Using c#, how to iterate through an multidimensional array of unknown dimensions?

例如考虑数组中的每个元素设定为指定的值,需要被迭代阵列的所有条目。该方法应该处理所有的下列情况,并填写所有条目的值4,无论通过阵列的尺寸。

For example consider setting each element of the array to a specified value, all entries of the array needs to be iterated. The method should handle all the following cases and fill all entries with the value 4, regardless of the dimension of the array passed.

ClearArray(new int[3], 4);
ClearArray(new int[3,3], 4);
ClearArray(new int[3, 3, 3, 3], 4);

该方法的签名显然看起来像

The methods signature obviously looks something like

static void ClearArray(Array a, int val) { ... }

我知道如何遍历的一个的尺寸:

for (int i=0; i<a.GetLength(dimension); i++) 
{
    ...
}

注意:这个问题是不是二维数组,数组的3D,4D也不阵列。它应该处理的任何尺寸上的阵列的排名属性对象说。

Note: This question is not about 2D arrays, 3D arrays, nor 4D arrays. It should handle whatever dimension the Rank property on the Array object says.

推荐答案

最快的解决方法是Buffer.BlockCopy:

Fastest solution is Buffer.BlockCopy:

static void ClearArray(Array array, int val)
{
  var helper = Enumerable.Repeat(val, Math.Min(array.Length, 1024)).ToArray();
  var itemSize = 4;


  Buffer.BlockCopy(helper, 0, array, 0, helper.Length * itemSize);
  for (var len = helper.Length; len < array.Length; len *= 2)
  {
    Buffer.BlockCopy(array, 0, array, len * itemSize, Math.Min(len, array.Length - len) * itemSize);
  }
}

static int Count(Array array, Func<int, bool> predicate)
{
  var helper = new int[Math.Min(array.Length, 4096)];
  var itemSize = 4;

  var count = 0;
  for (var offset = 0; offset < array.Length; offset += helper.Length)
  {
    var len = Math.Min(helper.Length, array.Length - offset);
    Buffer.BlockCopy(array, offset * itemSize, helper, 0, len * itemSize);
    for (var i = 0; i < len; ++i)
      if (predicate(helper[i]))
        count++;
  } 
  return count;
}

统计:

time: 00:00:00.0449501, method: Buffer.BlockCopy
time: 00:00:01.4371424, method: Lexicographical order
time: 00:00:01.3588629, method: Recursed
time: 00:00:06.2005057, method: Cartesian product with index array reusing
time: 00:00:08.2433531, method: Cartesian product w/o index array reusing

统计(计数功能):

Statistic (Count function):

time: 00:00:00.0812866, method: Buffer.BlockCopy
time: 00:00:02.7617093, method: Lexicographical order

code:

Code:

  Array array = Array.CreateInstance(typeof(int), new[] { 100, 200, 400 }, new[] { -10, -20, 167 });
  foreach (var info in new [] 
    { 
      new {Name = "Buffer.BlockCopy", Method = (Action<Array, int>)ClearArray_BufferCopy},
      new {Name = "Lexicographical order", Method = (Action<Array, int>)ClearArray_LexicographicalOrder}, 
      new {Name = "Recursed", Method = (Action<Array, int>)ClearArray_Recursed}, 
      new {Name = "Cartesian product with index array reusing", Method = (Action<Array, int>)ClearArray_Cartesian_ReuseArray}, 
      new {Name = "Cartesian product w/o index array reusing", Method = (Action<Array, int>)ClearArray_Cartesian}, 
    }
   )
  {
    var stopwatch = new Stopwatch();
    stopwatch.Start();
    var count = 10;
    for (var i = 0; i < count; ++i)
      info.Method(array, i);
    stopwatch.Stop();
    Console.WriteLine("time: {0}, method: {1}", TimeSpan.FromTicks(stopwatch.Elapsed.Ticks / count), info.Name);
  }