2

I have a linear array which I need to reshape as of a stack of 2D data. In this particular case, the stack only contains one element so the output should be an array with dimensions (height, width, 1).

This is related to a previous question, where I was asking about the same operation in the other direction (3D to 1D).

What is the fastest way to map this data to a 3D array?

I was planning to take the following approach:

    public static byte[, ,] ToBuffer3D<TDepth>(this byte[] buffer, int w, int h)
    {
        byte[, ,] buff3D = new byte[h, w, 1];

        for (int i = 0; i < buffer.Length; i++)
        {
            buff3D[(int)Math.Floor(i / (double)w), i % w, 0] = buffer[i];
        }

        return buff3D;
    }

But it seems like it might be possible to take advantage of how the data is already stored in memory to copy more than one element at a time. Is there some other mapping approach that could be employed in C#?

7
  • 1
    If it goes one way it goes the other. Do the same thing as your prior question just reverse the direction Commented Nov 4, 2014 at 12:36
  • 1
    possible duplicate of How to map a 3D array to a linear array? Commented Nov 4, 2014 at 12:36
  • 1
    @jodrell a jagged improves memory usage not performance Commented Nov 4, 2014 at 12:49
  • 1
    If this another API is .NET then there is no way to avoid copying data. In safe C# you can't just cast something to something different, like you could in C. I don't know about unsafe code, though. Commented Nov 4, 2014 at 12:51
  • 1
    @Hogan MD arrays are slower than 0 based jagged arrays. stackoverflow.com/questions/468832/… Commented Nov 4, 2014 at 15:20

2 Answers 2

2

This is likely to be somewhat faster:

public static byte[,,] ToBuffer3Da(this byte[] buffer, int w, int h)
{
    byte[,,] buff3D = new byte[h, w, 1];
    Buffer.BlockCopy(buffer, 0, buff3D, 0, h*w);
    return buff3D;
}
Sign up to request clarification or add additional context in comments.

Comments

1

if you use the base class and implementation defined below, you have a class that supports both linear and dimensional indexing at the same time. No conversion or copying is necessary.

Use it like this,

var matrix = new DecomposedMatrix<byte>(10, 10, 10)

foreach(var b int matrix)
{
    ...
}

for (var i = 0; i < matrix.Count; i++)
{
    ...
    var item = matrix[i];
    ...
}

for (var x = 0; x < matrix.H; x++)
for (var y = 0; y < matrix.W; y++)
for (var z = 0; z < matrix.D; z++)
{
    ...
    var item = matrix[x, y, z];
    ...
}

classes follow ...

public abstract class DecomposedMatrix
{
    private readonly int h;
    private readonly int w;
    private readonly int d;

    protected DecomposedMatrix(int h, int w, int d)
    {
        this.h = h;
        this.w = w;
        this.d = d;
    }

    public int W
    {
        get
        {
            return this.w;
        }
    }

    public int D
    {
        get
        {
            return this.d;
        }
    }

    public int H
    {
        get
        {
            return this.h;
        }
    }

    protected int DereferenceCoordinates(int x, int y, int z)
    {
        if (x >= this.H || y >= this.W || z >= this.D)
        {
            throw new IndexOutOfRangeException();
        }

        if (x < 0 || y < 0 || z < 0)
        {
            throw new IndexOutOfRangeException();
        }

        return z + (y * this.D) + (x * this.W * this.D);
    }
}

and the implementation

public class DecomposedMatrix<T> : DecomposedMatrix, IReadOnlyList<T>
{
    private readonly IList<T> data;

    public DecomposedMatrix(int h, int w, int d)
            : base(h, w, d)
    {
        this.data = new T[h * w * d];
    }

    public T this[int index]
    {
        get
        {
            return this.data[index];
        }

        set
        {
            this.data[index] = value;
        }
    }

    public T this[int x, int y, int z]
    {
        get
        {
            return this.data[this.DereferenceCoordinates(x, y, z)];
        }

        set
        {
            this.data[this.DereferenceCoordinates(x, y, z)] = value;
        }
    }

    public int Count
    {
        get
        {
            return this.data.Count;
        }
    }

    public IEnumerator<T> GetEnumerator()
    {
        return this.data.GetEnumerator();
    }

    public IEnumerator IEnumerable.GetEnumerator()
    {
        return this.data.GetEnumerator();
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.