Iterate through an arbitrary size array

Using C #, how to iterate through a multidimensional array of unknown dimensions?

For example, consider the possibility of setting each element of the array to a specified value, all entries in the array must be iterated. The method should handle all of the following cases and fill all records with a value of 4, regardless of the size of the transferred array.

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

The signature of the methods clearly looks something like this:

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

I know how to iterate over one dimension:

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

Note . This question does not concern two-dimensional arrays, three-dimensional arrays and 4D arrays. It must handle any dimension specified in the Rankin object Array.

+5
source share
5 answers

- 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

( ):

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

:

  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);
  }
+5

:
- "". "" , , "" ..

Func<Array, int[]> firstIndex = 
  array => Enumerable.Range(0, array.Rank)
         .Select(_i => array.GetLowerBound(_i))
         .ToArray();

Func<Array, int[], int[]> nextIndex = (array, index) => 
  {
    for (int i = index.Length-1; i >= 0; --i)
    {
       index[i]++;
       if (index[i] <= array.GetUpperBound(i))
         return index;
       index[i] = array.GetLowerBound(i);
    }
    return null;
  };

for (var index = firstIndex(array); index != null; index = nextIndex(array, index))
{
   var v = array.GetValue(index);
   ...
   array.SetValue(newValue, index);
}
+7

. : -1, . . .

:

static IEnumerable<IEnumerable<T>> CartesianProduct<T>(
    this IEnumerable<IEnumerable<T>> sequences) 
{ 
  IEnumerable<IEnumerable<T>> emptyProduct = 
    new[] { Enumerable.Empty<T>() }; 
  return sequences.Aggregate( 
    emptyProduct, 
    (accumulator, sequence) => 
      from accseq in accumulator 
      from item in sequence 
      select accseq.Concat(new[] {item})); 
}

, :

http://blogs.msdn.com/b/ericlippert/archive/2010/06/28/computing-a-cartesian-product-with-linq.aspx

. ?

var sequences = from dimension in Enumerable.Range(0, array.Rank)
        select Enumerable.Range(array.GetLowerBound(dimension), array.GetLength(dimension));

, , :

{
   { 0, 1, 2 },
   { 0, 1, 2, 3 }
}

:

var product = sequences.CartesianProduct();

,

{
   { 0, 0 },
   { 0, 1 },
   { 0, 2 },
   { 0, 3 },
   { 1, 0 },
   { 1, 1 },
   { 1, 2 },
   { 1, 3 },
   { 2, 0 },
   { 2, 1 },
   { 2, 2 },
   { 2, 3 }
}

foreach(IEnumerable<int> indices in product)
    array.SetValue(value, indices.ToArray());
?
+6

, :

    public static void ClearArray(Array a, int val)
    {
        int[] indices = new int[a.Rank];
        ClearArray(a, 0, indices, val);
    }

    private static void ClearArray(Array a, int r, int[] indices, int v)
    {
        for (int i = 0; i < a.GetLength(r); i++)
        {
            indices[r] = i;

            if (r + 1 < a.Rank)
                ClearArray(a, r + 1, indices, v);
            else
                a.SetValue(v, indices);
        }
    }
+2

Array.Rank , Array.GetLowerBound(int dimension) Array.GetUpperBound(int dimension), .

, (, - ). ClearArray() .

a.SetValue( , params int []), , ClearArray.

0

All Articles