Я получил следующие коды:
Boo[,,] boos = new Boo[8, 8, 8];
Boo GetMe(int i, int j, int k)
{
return boos[i, j, k];
}
Приведенный выше код неэффективен, поэтому я конвертирую его в одномерный массив:
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[?];
}
Как я могу получить Boo (из той же позиции, что и в многомерном массиве jkl) из одномерного массива boosone?





Не совсем уверен, почему вы говорите, что первый 3D-массив неэффективен (я имею в виду, действительно ли вы заметили особенно сильное замедление при его использовании?), но вы можете сделать это с помощью некоторых простых вычислений смещения.
Прежде всего, если вы ориентируетесь на последнюю версию C#, вы можете заменить всю функцию копирования всего двумя строками, и тогда ваш код будет выглядеть так:
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];
}
Если вы по какой-то причине не хотите использовать класс MemoryMarshal, вы также можете использовать LINQ для выравнивания вашего 3D-массива, хотя этот подход гораздо менее эффективен:
boosone = boos.Cast<Boo>().ToArray();
Под неэффективностью я подразумеваю сильное замедление.
Я понимаю, что 3D-массивы могут иметь некоторые дополнительные накладные расходы для получения целевых смещений, но общая сложность алгоритма все равно остается прежней. Но если вам нужен линейный массив, то этот код должен отлично справляться с этой задачей, а также избавляться от тех трех циклов, которые вы использовали для копирования массива в одномерный.
Этот код выдает исключение, если вы это сделаете GetMe(7, 7, 7);IndexOutOfRangeException
@PiotrKFtw - Насколько велики ваши массивы, чтобы они замедляли работу?
@PiotrKFtw Извините, я опечатался в индексах в последней строке, теперь я это исправил.
Я использую их в больших циклах, и цикл занимает 300-400 мс и тратит впустую производительность процессора для завершения при использовании многомерного массива, в то время как без его использования для завершения требуется 80 мс и намного меньше производительности процессора.
@PiotrKFtw Опять же, я действительно не понимаю, почему это так, но, тем не менее, мой ответ по-прежнему действителен для вашего вопроса, поскольку он делает именно то, что вы просили. Почему вы удалили отметку как действительную?
int index = (8 * 8 * i) + (8 * j) + k;
return boosone[index];
Доступ к многомерному массиву не медленнее, чем доступ к одномерному массиву, на самом деле они оба хранятся в памяти точно так же. Дело не в том, что вы делаете, а в том, как вы это делаете.
Если вы хотите обернуть какой-либо массив тривиальным методом, дайте компилятору подсказку, что он может быть встроенным
[MethodImpl(MethodImplOptions.AggressiveInlining)]
Boo GetMe(int i, int j, int k)
{
return boos[i, j, k];
}
Сказав это, этот метод абсолютно ничего не делает и не имеет никаких преимуществ, чем просто использование индексатора массива.
Если вы хотите работать с сегментами массива без накладных расходов на перераспределение, рассмотрите возможность использования Span<T> или Memory<T> или ArraySegment
Примерно в этот момент я бы написал пример кода, однако, поскольку я понятия не имею, что вы делаете, трудно догадаться, что вам нужно.
Я предлагаю скачать БенчмаркДотнет и начать профилировать свой код, чтобы выяснить, какой из них является наиболее эффективным и производительным способом сделать то, что вы хотите, не гадайте...
Почему бы вам не взглянуть на зубчатые массивы, которые обеспечивают лучшую производительность? Я сделал тест (в конфигурации RELEASE), который показал, что ваша оболочка в два раза быстрее, чем массив d3, но jagged в 3 раза быстрее, чем массив d3.
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}");
}
}
}
Выход:
d3Array 15541709
wrapped 8213316
jagged 5322008
Я также проанализировал использование процессора.
Она одинакова для всех 3-х подходов.
Важна не только скорость, но и мощность процессора.
Я провел дополнительное тестирование. Загрузка ЦП в порядке для зубчатого массива. См. правки к ответу.
"что неэффективно", что неэффективно и почему неэффективно?