Передать массив внутри многомерного массива функции в C#

Я пытаюсь взять трехмерный массив и передать его в функцию, но она продолжает сообщать об ошибке из-за неправильного количества индексов внутри []. Я передаю ему 2 значения, чтобы вернуть массив для функции, но мне требуется поместить 3 значения для одного элемента, а не массива.

public void function(int[]) {
    // does something
}

static void Main(String[] args) {
    int[,,] 3Darr = {{{1,2,3}, {4,5,6}, {7,8,9}}, {{10,11,12}, {13,14,15}, {16,17,18}}};
    
    function(arr[1,2]); // gets error for not passing 3 values
}

Какой тип arr? Я вижу объявленный 3Darr, но не arr (я не думаю, что 3Darr является допустимым символом C#, не так ли?). Рассмотрите возможность переформатирования выражения инициализации массива, его очень трудно читать (по крайней мере, на моем телефоне).

Flydog57 27.05.2024 20:38

Кстати, C# позволяет создавать объект, который действует так же, как если бы он был массивом. Вы можете создать объект, который действует как int[,] или int[,,], из любой коллекции, используя индексированные свойства (также называемые индексаторами). Вот пример: stackoverflow.com/questions/69286156/…

Flydog57 27.05.2024 21:02
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
59
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

int[,,] — трехмерный массив; к нему можно получить доступ только по всем трем координатам, и результатом этого поиска будет int, а не int[]. Не существует механизма получения int[] от int[,,].

Интересно, возможно, вы имеете в виду неровный массив, поэтому один из:

  • int[][][]
  • int[,][]
  • int[][,]

В качестве альтернативы вы можете получить Span<int> как фрагмент смежных данных из int[,,], просто используя начальную точку ref arr[x,y,z] и количество элементов. В широком смысле диапазон можно сравнить с массивом/вектором (по крайней мере, концептуально).

Span будет работать только в последнем измерении, смотрите мой ответ.
Charlieface 28.05.2024 03:12
Ответ принят как подходящий

Вам следует использовать зубчатый массив (массив массива массива) int[][][] вместо трехмерного int[,,]:

int[][][] arr = new int[][][] {
  new int[][] {
    new int[] {1, 2, 3},
    new int[] {4, 5, 6},
    new int[] {7, 8, 9},
  },

  new int[][] {
    new int[] {11, 12, 13},
    new int[] {14, 15, 16},
    new int[] {17, 18, 19},
  },
}; 

function(arr[1][2]);

Если измерение, по которому вы хотите выполнить итерацию, является последним (т. е. вы указали все остальные), то вы можете использовать Span<T> со следующими функциями расширения

public static Span<T> AsSpan<T>(this Array array) =>
    MemoryMarshal.CreateSpan(ref Unsafe.As<byte, T>(ref MemoryMarshal.GetArrayDataReference(array)), array.Length);

public static Span<T> SliceLastDim<T>(this T[,,] array, int dim1, int dim2) =>
    array.AsSpan<T>().Slice(((dim1 * array.GetLength(0)) + dim2) * array.GetLength(1), array.GetLength(2));

Затем, чтобы получить нужную строку, просто умножьте остальные измерения.

public void function(Span<int> span)
{
    // does something
}

static void Main(String[] args)
{
    int[,,] _3Darr = {{{1,2,3}, {4,5,6}, {7,8,9}}, {{10,11,12}, {13,14,15}, {16,17,18}}};
    var span = _3Darr.SliceLastDim(1, 2);
    function(span);
}

dotnetfiddle

Более общее решение могло бы нарезать произвольное количество измерений. Опять же, указанные вами размеры идут справа налево, а остальные нарезаются. Результат - единственный Span<T>.

public static Span<T> Slice2D<T>(this Array array, params int[] dims)
{
    if (dims.Length >= array.Rank - 1)
        throw new InvalidOperationException("Too many dimensions");

    var offset = 0;
    for (var i = 0; i < dims.Length; i++)
        offset = (offset + dims[i]) * array.GetLength(i);

    var size = 1;
    for (var i = dims.Length; i < array.Rank; i++)
        size *= array.GetLength(i);

    return array.AsSpan<T>().Slice(offset, size);
}

Другие вопросы по теме