user10311801
user10311801

Reputation:

How can I access multi dimension in one dimension array?

I got the following codes:

Boo[,,] boos = new Boo[8, 8, 8];
Boo GetMe(int i, int j, int k)
{
    return boos[i, j, k];
}

The code above is inefficient so i convert it to one dimensional array:

Boo[] boosone;
Boo[,,] boos = new Boo[8, 8, 8];
Boo GetMe(int i, int j, int k)
{
   if (boosone == null)
   {
       boosone = new Boo[8 * 8 * 8];
       int num = 0;
       for (int x = 0; x < 8; x++)
       {
           for (int y = 0; y < 8; y++)
           {
               for (int z = 0; z < 8; z++)
               {
                   boosone[num] = boos[x, y, z];
                   num++;
               }
           }
       }
    }
    return boosone[?];
}

How can I get the Boo (from the same position like in multidimensional array j k l) from the one dimensional array boosone?

Upvotes: 0

Views: 170

Answers (4)

TheGeneral
TheGeneral

Reputation: 81593

Accessing a multi dimensional array isn't any slower then accessing a single dimension array, in fact they are both stored in memory exactly the same way. It's not what you are doing, it's how you are doing it.

If you want to wrap either array in a trivial method, give the compiler a hint that it can be inline

[MethodImpl(MethodImplOptions.AggressiveInlining)]
Boo GetMe(int i, int j, int k)
{
    return boos[i, j, k];
}

On saying that, this method does absolutely nothing and has no advantage then just using the array indexer.

If you want to work with segments of an array with out the overhead of reallocation, consider using Span<T> or Memory<T> or ArraySegment

At about this point I would write example code, however as I have no idea what you are doing, it's hard to guess what you need.

What I suggest, is download BenchmarkDotNet, and start profiling your code to work out what is the most efficient and performant way to do what you desire, don't guess...

Upvotes: 2

CSDev
CSDev

Reputation: 3235

Why don't you look at jagged arrays which provide better performance? I did a test (under RELEASE configuration) which showed that you wrapper is twice faster than the d3 array, but jagged is 3 times faster than the d3 array.

using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;

namespace ArrayWrapper
{
    class ArrayPerformanceTest
    {
        int xSize = 2;
        int ySize = 3;
        int zSize = 4;
        int count = 100000000;
        int delay = 500;

        static void Main(string[] args)
        {
            new ArrayPerformanceTest().Run();
        }

        private void Run()
        {

            var d3Array = CreateD3Array();
            var wrapped = GetD1Adapter(d3Array);
            var jagged = GetJaggedArray(d3Array);

            Thread.Sleep(delay);
            TestD3Array(d3Array);
            Thread.Sleep(delay);
            TestWrappedArray(wrapped);
            Thread.Sleep(delay);
            TestJaggeddArray(jagged);
            Thread.Sleep(delay);
        }

        private int[,,] CreateD3Array()
        {
            var rectangular = new int[xSize, ySize, zSize];

            int i = 7;
            for (var x = 0; x < xSize; x++)
                for (var y = 0; y < ySize; y++)
                    for (var z = 0; z < zSize; z++)
                        rectangular[x, y, z] = ++i;

            return rectangular;
        }

        private int[] GetD1Adapter(int[,,] d3Array)
        {
            return d3Array.Cast<int>().ToArray();
        }

        private int[][][] GetJaggedArray(int[,,] d3Array)
        {
            var xSize = d3Array.GetUpperBound(0) + 1;
            var ySize = d3Array.GetUpperBound(1) + 1;
            var zSize = d3Array.GetUpperBound(2) + 1;

            var jagged = new int[xSize].Select(j => new int[ySize].Select(k => new int[zSize].ToArray()).ToArray()).ToArray();

            for (var x = 0; x < xSize; x++)
                for (var y = 0; y < ySize; y++)
                    for (var z = 0; z < zSize; z++)
                        jagged[x][y][z] = d3Array[x, y, z];

            return jagged;
        }

        private void TestD3Array(int[,,] d3Array)
        {
            int i;
            var sw = new Stopwatch();
            sw.Start();
            for (var c = 0; c < count; c++)
                for (var x = 0; x < xSize; x++)
                    for (var y = 0; y < ySize; y++)
                        for (var z = 0; z < zSize; z++)
                            i = d3Array[x, y, z];
            sw.Stop();
            Console.WriteLine($"{nameof(d3Array),7} {sw.ElapsedTicks,10}");
        }

        private void TestWrappedArray(int[] wrapped)
        {
            int i;
            var sw = new Stopwatch();
            sw.Start();
            for (var c = 0; c < count; c++)
                for (var x = 0; x < xSize; x++)
                    for (var y = 0; y < ySize; y++)
                        for (var z = 0; z < zSize; z++)
                            i = wrapped[x * ySize * zSize + y * zSize + z];
            sw.Stop();
            Console.WriteLine($"{nameof(wrapped),7} {sw.ElapsedTicks,10}");
        }

        private void TestJaggeddArray(int[][][] jagged)
        {
            int i;
            var sw = new Stopwatch();
            sw.Start();
            for (var c = 0; c < count; c++)
                for (var x = 0; x < xSize; x++)
                    for (var y = 0; y < ySize; y++)
                        for (var z = 0; z < zSize; z++)
                            i = jagged[x][y][z];
            sw.Stop();
            Console.WriteLine($"{nameof(jagged),7} {sw.ElapsedTicks,10}");
        }
    }
}

Output:

d3Array   15541709
wrapped    8213316
 jagged    5322008

I also analysed CPU usage.

enter image description here

It is of the same rate for all 3 approaches.

Upvotes: -2

Sergio0694
Sergio0694

Reputation: 4577

Not really sure why you're saying that the first 3D array is not efficient (I mean, have you actually noticed a particularly heavy slowdown when using it?), but you can do that with some simple offset calculations.

First of all, if you target the latest C# version, you can replace the whole copy function with just two lines, and your code would then look like this:

using System;
using System.Runtime.InteropServices;

Boo[] boosone;
Boo[,,] boos = new Boo[8, 8, 8];

Boo GetMe(int i, int j, int k)
{
    if (boosone == null)
    {
        boosone = new Boo[boos.Length];
        MemoryMarshal.CreateSpan(ref boos[0, 0, 0], boosone.Length).CopyTo(boosone);
    }

    return boosone[boos.GetLength(1) * boos.GetLength(2) * i + boos.GetLength(2) * j + k];
}

If you don't want to use the MemoryMarshal class for some reason, you could also use LINQ to flatten your 3D array, although this approach is much less efficient:

boosone = boos.Cast<Boo>().ToArray();

Upvotes: 2

elgaspar
elgaspar

Reputation: 468

int index = (8 * 8 * i) + (8 * j) + k;
return boosone[index];

Upvotes: 2

Related Questions