Home > Blockchain >  Filling a multidimensional array in c# without loops with single value
Filling a multidimensional array in c# without loops with single value

Time:08-18

Is there a way in C# to set each value of a multidimensional array to a specific value without using loops? I found Array.Fill but it seems to only work for a 1D-Array.

Basically what I'm looking for is something like:

double[,,,] arrayToFill = new double[7,8,9,10];
Array.FillWhole(arrayToFill, 1.2345);

Of course one could just use nested loops but isn't that annoying when working with higher dimensional arrays?

CodePudding user response:

(See the last code sample in this answer for the best solution.)

You can actually use a Span<T> to do this, but it looks quite fiddly!

double[,,,] arrayToFill = new double[7, 8, 9, 10];

var data = MemoryMarshal.CreateSpan(
    ref Unsafe.As<byte, double>(ref MemoryMarshal.GetArrayDataReference(arrayToFill)),
    arrayToFill.Length);

data.Fill(1.2345);

foreach (var value in arrayToFill)
{
    Console.WriteLine(value);  // All values are 1.2345
}

You can write a method to encapsulate this:

public static void FillArray<T>(Array array, T value)
{
    var data = MemoryMarshal.CreateSpan(
        ref Unsafe.As<byte, T>(ref MemoryMarshal.GetArrayDataReference(array)),
        array.Length);

    data.Fill(value);
}

Then the call site becomes a lot more readable:

double[,,,] arrayToFill = new double[7, 8, 9, 10];

FillArray(arrayToFill, 1.2345);

foreach (var value in arrayToFill)
{
    Console.WriteLine(value);  // All values are 1.2345
}

If you want to get more fancy you can encapsulate this in an extension method:

public static class ArrayExt
{
    public static void Fill<T>(this Array array, T value)
    {
        var data = MemoryMarshal.CreateSpan(
            ref Unsafe.As<byte, T>(ref MemoryMarshal.GetArrayDataReference(array)),
            array.Length);

        data.Fill(value);
    }
}

Then you can call it like so:

double[,,,] arrayToFill = new double[7, 8, 9, 10];

arrayToFill.Fill(1.2345);

foreach (var value in arrayToFill)
{
    Console.WriteLine(value);  // All values are 1.2345
}

IMPORTANT! You must ensure that you use the correct type with which to fill the array. If you specify the wrong type it will fill the array with rubbish, for example:

arrayToFill.Fill(1);

will really mess things up.

In this example you'd need to do arrayToFill.Fill<double>(1); to specify the correct type because otherwise it will infer the wrong type for filling the array.

As per comments from /u/charlieface, you can circumvent this issue by adding strongly-typed overloads for each array dimension, thusly:

This is probably the best approach:

public static class ArrayExt
{
    public static void Fill<T>(this T[,]    array, T value) => fill(array, value);
    public static void Fill<T>(this T[,,]   array, T value) => fill(array, value);
    public static void Fill<T>(this T[,,,]  array, T value) => fill(array, value);
    public static void Fill<T>(this T[,,,,] array, T value) => fill(array, value);

    static void fill<T>(Array array, T value)
    {
        var data = MemoryMarshal.CreateSpan(
            ref Unsafe.As<byte, T>(ref MemoryMarshal.GetArrayDataReference(array)),
            array.Length);

        data.Fill(value);
    }

    // ...etc etc. But does anyone really need more than a 5D array? ;)
}

Then arrayToFill.Fill(1); will work correctly.


Also see this post from /u/charlieface

CodePudding user response:

As mentioned by @MatthewWatson, my extension method in a different answer allows you to get a Span<T> of a two dimensional array.

But it's risky, as it leaves it open to the caller as to which data type to actually fill it with. Instead, create the extension methods with the exact rank you need, for example T[,,]

public static Span<T> AsSpan<T>(this T[,,] array)
{
    return MemoryMarshal.CreateSpan(ref Unsafe.As<byte, T>(ref MemoryMarshal.GetArrayDataReference(array)), array.Length);
}

Then you use Span.Fill

double[,,,] arrayToFill = new double[7,8,9,10];
arrayToFill.AsSpan().Fill(1.2345);

You need a different extension for each rank, such as AsSpan<T>(this T[,] array) and AsSpan<T>(this T[,,] array).

CodePudding user response:

its not loops are amazing on arrays you just got to get used to it.

how to fill a Multi-dim array;

int **inpu**;
for(i...;i  ){
  for(j...;j  )
  {
   //here you can set your input value how ever you want
   //input  = i   j; or cin << **input**;
   array[i][j] = **inpu**;
  }
}

some times its better using loops than using a unknown function that probably is using loops to fill your arrays and takes more time the finish the task.

  • Related