PBrenek
PBrenek

Reputation: 571

c# assign 1 dimensional array to 2 dimensional array with shifting values

I have a vector (1D array) of double values, say X. I need to copy this vector of values into a matrix (2D array), say Y, such that the first row of Y is the same as X transposed, the second row is the same as X shifted one value to the left, the third row of Y is the same as X shifted two values to the left and so on.

For example,

X = { 1.0, 2.0. 3.0, 4.0, 5.0 }

and I need

Y =  1.0  2.0  3.0  4.0  5.0
     2.0  3.0  4.0  5.0  0.0
     3.0  4.0  5.0  0.0  0.0
     4.0  5.0  0.0  0.0  0.0
     5.0  0.0  0.0  0.0  0.0

Some time ago Mathew Finlay posted code for copying 1D array to a 2D array for value types. I have modified the code as follows:

for (int targetRow = 0; targetRow < N; targetRow++)
{
    Buffer.BlockCopy
    (
        X,                                                    // 1D source array
        0,                                                    // source array offset
        Y,                                                    // 2D target (destination) array
        targetRow * Y.GetLength(targetRow) * sizeof(double),  // target array offset
        X.Length * sizeof(double)                             // count
    );
}

I am not sure if this will do the trick and more importantly, whether this is the best way of doing this. This is part of a larger code and this part needs to be fast and efficient as the vector X and the matrix Y can get very large.

Also, to complicate things a bit more, I may sometines not require the full length (all the values) of vector X but only part of it so the matrix Y could be N x M where M <= N. I am not sure how to handle this in the code above.

Thank you in advance for any help or suggestions you may be able to provide.

EDIT: For those interested, here are some performance results.

I ran some speed tests on the two types of code suggested here (looping and Buffer.BlockCopy) and the results surprised me. I will designate the Buffer.BlockCopy as BC and looping as L. For 10x10 matrix BC = 00:00:00.0000017 and L = 00:00:00.0000030. For 100x100 matrix BC = 00:00:00.0000293 and L = 00:00:00.0000710. Finally, for 1000x1000 matrix BC = 00:00:00.0065340 and L = 00:00:00.0138396. So the Buffer.Block copy seems to outperform looping even for small matrices. I ran this on a Win 7 Ultimate (64) machine.

Upvotes: 1

Views: 1670

Answers (2)

Sam
Sam

Reputation: 7313

What about?

       double[] X = new double[]{ 1.0, 2.0, 3.0, 4.0, 5.0 };

        var lbound = X.GetLowerBound(0);
        var ubound = X.GetUpperBound(0);

       double[,] Y = new double[ubound + 1, ubound + 1];

       for (var i = lbound; i <= ubound; i++)
       {
           for (var j = lbound ; j <= ubound ; j++)
           {
               Y[i, j] = (i + j) > ubound ? 0.0 : X[i +j];
           }  
       }

Edit

This works:

 for (int targetRow = 0; targetRow <= ubound; targetRow++)
  {
    Buffer.BlockCopy
    (
        X,                                        // 1D source array
        targetRow * sizeof(double),               // source array offset
        Y,                                        // 2D target (destination) array
        (targetRow * X.Length) * sizeof(double),  // target array offset
        (X.Length - targetRow) * sizeof(double)  // count
    );
}


for (var i = 0; i <= ubound; i++)
{
    for (var j = 0; j <= ubound; j++)
    {
        Console.Write(Y[i, j] + " ");
    }
    Console.WriteLine();
}

Console.ReadKey();

Array Offset


2nd Edit

To deal with your other requirement of changing 2nd dimension of the destination array, you need to change some of the BlockCopy parameters targetArrayOffset and count, you can map them to the dimension of the destination array as below.

        double[] X = new double[] { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0 };

        var lbound = X.GetLowerBound(0);
        var ubound = X.GetUpperBound(0);

       double[,] Y = new double[X.Length, 3];

        int yLen = Y.GetUpperBound(1) + 1;

for (int targetRow = 0; targetRow <= ubound; targetRow++)
{
    Buffer.BlockCopy
    (
        X,                                      // 1D source array
        (targetRow * sizeof(double)),             // source array offset
        Y,                                        // 2D target (destination) array
        ((targetRow * yLen) * sizeof(double)),// target array offset
        ((X.Length - targetRow) > yLen ? yLen : (X.Length - targetRow))  * sizeof(double)  // count
    );
}

output:

ScreenPrint

Upvotes: 1

Jeppe Stig Nielsen
Jeppe Stig Nielsen

Reputation: 62002

Assuming x is of type double[], use:

var y = new double[x.Length, x.Length];
for (int row = 0; row < x.Length; ++row)
{
  for (int col = 0; col < x.Length - row; ++col)
  {
    y[row, col] = x[col - row];
  }
}

or similar.

Upvotes: 0

Related Questions