0

Having the following:

        int[,] a = new int[4, 2];
        int[] b = new int[2];

how do I copy values from b into the first element of a? What's wrong with b.CopyTo(a[0])?

jackhab
  • 17,128
  • 37
  • 99
  • 136
  • I would use `int[][] a`, because it's faster than `int[,]` and also your `b.CopyTo(a[0])` should work just fine – Alexey S. Larionov Aug 16 '21 at 11:32
  • Does this answer your question? [Copy single row from multidimensional array into new one dimensional array](https://stackoverflow.com/questions/34986250/copy-single-row-from-multidimensional-array-into-new-one-dimensional-array) and [c# assign 1 dimensional array to 2 dimensional array syntax](https://stackoverflow.com/questions/1099266/c-sharp-assign-1-dimensional-array-to-2-dimensional-array-syntax) and [How to get a dimension (slice) from a multidimensional array](https://stackoverflow.com/questions/4801990/) –  Aug 16 '21 at 11:38
  • Is this to work only for primitives types (`int`, `double`) or for any user type? – John Alexiou Aug 16 '21 at 12:08

4 Answers4

1

You can access a only by using 2 coordinates (so a[x,y]) because it is defined using 2 dimensions.

Try using int[][] a instead, if you do that then a becomes an array containing 1-dimensional subarrays, and then you can use 1 coordinate to access a subarray.

Example code:

int[][] a = new int[4][];
a[0] = new int[2];
int[] b = new int[2];

Note that after this, when I try do to b.CopyTo(a[0]) I get a "The call is ambiguous " compilation error (in .NET 5) because there two different extension methods that both match the CopyTo signature...

Peter B
  • 22,460
  • 5
  • 32
  • 69
  • Thanks, so what's the difference between declaring int[][] and int[,]? – jackhab Aug 16 '21 at 11:56
  • @jackhab `int[][]` is a [jagged array](https://www.tutorialsteacher.com/csharp/csharp-jagged-array) and `int[,]` is a [two dimentional array](https://www.tutorialsteacher.com/csharp/csharp-multi-dimensional-array) • https://stackoverflow.com/questions/597720/ • https://stackoverflow.com/questions/4648914/ • https://www.tutorialspoint.com/csharp/csharp_arrays.htm –  Aug 16 '21 at 11:58
  • So, from what I understand, an element of two-dimensional array is not a one-dimensional array (as in C) and this is why I have to use jagged array, right? – jackhab Aug 16 '21 at 12:01
  • @jackhab A two dimensional array in C is a two dimentional array even being a one dimentional array in the memory no matter the language. But in C indeed you can use pointers from the first cell and manage the matrix indexes and ranges factors yourself to optimize like for images. In C# there is no such a thing and you need to get a reference to the raw buffer to do that like using unsafe code or any method provided by some classes. https://learn.microsoft.com/dotnet/csharp/language-reference/unsafe-code –  Aug 16 '21 at 12:04
0

What's wrong with b.CopyTo(a[0])?

A is a two dimensional array, so you need two indices, i.e. a[0,0] = b[0]

Instead of using the built in multidimensional array I would suggest using a wrapper around a 1D array instead, with a indexer something like this:

public T this[int x, int y]
{
    get => Data[y * Width + x];
    set => Data[y * Width + x] = value;
}

This has the advantage of easier interoperability, since many system exposes 2D buffers of various kinds as 1D data + size. This allows copying data to be done by a block copy instead of copying element by element.

JonasH
  • 28,608
  • 2
  • 10
  • 23
0

For primitives array types you can define extension methods for packing or unpacking arrays using the Buffer.BlockCopy();

static class Program
{
    static void Main(string[] args)
    {
        int[,] A = new[,] { { 1, 2 }, { 3, 4 } };
        int[] data = A.PackMarix();
        int[,] B = data.UnPackMarix(2, 2);

        Console.WriteLine(B);
    }

    public static int[,] UnPackMarix(this int[] data, int rows, int columns)
    {
        int[,] result = new int[rows, columns];
        int bytes = Buffer.ByteLength(data);
        Buffer.BlockCopy(data, 0, result, 0, bytes);
        return result;
    }
    public static int[] PackMarix(this int[,] data)
    {
        int[] result = new int[data.Length];
        int bytes = Buffer.ByteLength(data);
        Buffer.BlockCopy(data, 0, result, 0, bytes);
        return result;
    }
}

For non-primitive types you have to do the copying manually

    public static T[,] UnPackMarix<T>(this T[] data, int rows, int columns) 
    {
        var result = new T[rows, columns];
        for (int i = 0; i < rows; i++)
        {
            for (int j = 0; j < columns; j++)
            {
                result[i, j] = data[i * columns + j];
            }
        }
        return result;
    }
    public unsafe static T[] PackMarix<T>(this T[,] data)
    {
        var result = new T[data.Length];
        int rows = data.GetLength(0);
        int columns = data.GetLength(1);
        for (int i = 0; i < rows; i++)
        {
            for (int j = 0; j < columns; j++)
            {
                result[i * columns + j] = data[i, j];
            }
        }
        return result;
    }
John Alexiou
  • 28,472
  • 11
  • 77
  • 133
0

This has been posted on SO before but I couldn't find the old post. Anyway, use the Microsoft High Performance toolkit. It has spans for 2D memory. With that you can do this:

        int[,] a = new int[4, 2];

        int[] b = { 1, 2 };

        var spanB = b.AsSpan();
        var spanA = a.AsSpan2D();

        spanB.CopyTo(spanA.GetRowSpan(0));

        foreach (var i in spanA)
            Console.WriteLine(i);
MikeJ
  • 1,299
  • 7
  • 10