Как создать многомерный ImmutableArray?

Похоже, что документация MS по ImmutableArray относится только к одномерному массиву. Кажется, я смогу обернуть весь массив в ImmutableArray, затем сначала получить весь массив (по индексу 0), а затем получить конкретное значение, скажем, [i, j].

ImmutableArray<T[,]> arr = ImmutableArray.Create<TVal[,]>(oneDimArray);
T value = arr[0][i, j];

Многомерные массивы кажутся мне обычной потребностью, и должен быть лучший способ. Спасибо за помощь!

«Многомерные массивы кажутся мне обычной необходимостью». Они не. Многомерные массивы часто используются в учебных упражнениях, но помимо этого, как правило, существуют лучшие структуры данных. У них есть некоторые законные виды использования, например. вы можете использовать его для представления шахматной доски, но больше учебных упражнений имитируют ситуации, когда более уместным является одномерный массив или простой список элементов с несколькими свойствами.

jmcilhinney 11.11.2022 03:19

Что касается вашего примера здесь, я сомневаюсь, что он полезен. Я никогда не использовал ImmutableArray, но я предполагаю, что это означает, что вы не можете присваивать новые значения его элементам. Это не помешает вам получить значение элемента и изменить этот объект, поэтому ничто не помешает кому-то изменить элементы вашего 2D-массива внутри этого ImmutableArray.

jmcilhinney 11.11.2022 03:20

@jmcilhinney Я думал, что массив - это тип значения. Это глупо, потому что если массив имеет тип значения, то нет необходимости снова оборачивать его в ImmutableArray. Спасибо за комментарии.

DavidY 11.11.2022 15:00
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
57
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я согласен с комментариями jmcilhinney о том, что многомерные массивы нужны редко, но, возможно, это просто мой ограниченный опыт после десятилетий работы разработчиком серверной части и предприятия. Возможно, есть другие области (разработка игр?), где они нужнее...

Тем не менее, вы часто можете использовать зубчатые массивы вместо многомерных массивов. Это также возможно с ImmutableArray<T>, хотя с ним не всегда легко работать.

В качестве примера, вот как инициализировать неизменяемый зубчатый массив размером n×m со значением по умолчанию:

public static ImmutableArray<ImmutableArray<T>> Initialize<T>(int n, int m, T initialValue)
{
    var inner = Enumerable.Range(1, m).Select(_ => initialValue).ToImmutableArray();
    return Enumerable.Range(1, n).Select(_ => inner).ToImmutableArray();
}

Вот пример того, как инициализировать массив 2×3 со значением по умолчанию "foo":

var arr1 = Jagged.Initialize(2, 3, "foo");

«Изменение» значений внутри него в лучшем случае неудобно:

// Change value at (0, 1)
var arr2 = arr1.Select(
    (a, i) => a.Select(
        (s, j) => i == 0 && j == 1 ? "bar" : s).ToImmutableArray()).ToImmutableArray();

Однако в зависимости от того, для чего вам это нужно, вы можете написать вспомогательные методы, чтобы упростить такие проекции.

Поскольку зубчатый массив неизменяем, приведенное выше выражение не изменяет исходный массив arr1, а возвращает новый зубчатый массив arr2.

С другой стороны, поиск данных прост:

// Retrieve value at (0, 1)
string bar = arr2[0][1];

Как и ожидалось, bar имеет значение "bar".

Я часто работаю с неизменяемыми структурами данных в C#, но обычно придерживаюсь IEnumerable<T>. Возможно, вы заметили, что приведенная выше проекция в любом случае интенсивно использует LINQ, поэтому, если у вас нет огромных объемов данных, неясно, зачем вам что-то вроде ImmutableArray, зубчатое или нет...

Спасибо за ответ! Я это попробую. Просто любопытно, в каких случаях вы бы придерживались IEnumerable<T>? Является ли это интерфейсом и может иметь тип реализации, который не является неизменным. В каких случаях неизменяемость не нужна?

DavidY 11.11.2022 15:06

@DavidY В интерфейсе IEnumerable<T> нет методов, допускающих мутацию, поэтому все, что вы можете с ним делать, — это фильтровать, проецировать, сворачивать и т. д.

Mark Seemann 11.11.2022 17:43

Привет @Mark Seemann, я попробовал зубчатый массив, который вы предложили как для IEnumerable, так и для ImmutableArray. Это сработало, но, похоже, работает только для небольшого количества элементов. Например, если я попытаюсь построить массив 1000 на 1000, это вызовет переполнение стека. Я также попробовал простой массив IEnumerable и Immutable для большого количества элементов, скажем, 1 000 000, а также получил переполнение стека. Должен ли я использовать его только для небольшого количества элементов?

DavidY 12.11.2022 15:05

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

DavidY 12.11.2022 15:43

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