Reputation:
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
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
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.
It is of the same rate for all 3 approaches.
Upvotes: -2
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