Лучший способ «обернуть» список массивов в Java?

#java #arraylist #multidimensional-array

#java #список массивов #многомерный массив

Вопрос:

Я хотел бы представить матричные данные в подходящей структуре данных на Java. Размеры этой матрицы зависят от пользовательского ввода. Вероятно, одним из способов было бы использовать «волшебную» максимальную константу и использовать простой многомерный массив. Но операции с данными сильно зависят от измерения, и я хотел бы избегать фиксированных массивов, поскольку мне всегда нужно отслеживать используемое и максимальное измерение. Более динамичный подход, конечно, заключается в определении чего-то вроде

 private ArrayList<ArrayList<ArrayList<Point>>> arr3d = new ArrayList<ArrayList<ArrayList<Element>>>();
  

Я думаю, что это неприемлемо некрасиво. Возможно, было бы лучше определить пользовательскую структуру данных, то есть одномерный список массивов (или вектор), а затем каким-то образом обернуть это, т. Е. Сопоставить доступ, указанный как [i, j, k], с некоторым элементом этого единого списка. Возможно ли перезаписать оператор []? Как сделать это эффективно? Есть ли какая-нибудь существующая библиотека или код, на которые я мог бы опереться?

PS: Я думал, что это может быть распространенной проблемой, но, несмотря на все усилия, я не нашел существующего вопроса. Заранее извиняюсь, если я пропустил какой-то ответ.

Комментарии:

1. Я все еще не понимаю, почему не использовать массивы…

2. @m0skit0 Потому что вы должны статически объявить их количество измерений (т. Е. double[][] vs double[][][] ), и в op говорится, что это должно быть определено во время выполнения. (Я думаю)

Ответ №1:

Почему бы вам не создать свой собственный класс для этого? Он может содержать ваш 3D-список внутри, но вы предоставляете только «удобные» методы для доступа и установки элементов.

И нет, в Java невозможно перегрузить []

Быстрый помощник для этого:

 public class Cube<T> {
    private final List<List<List<T>>> elements = new ArrayList<List<List<T>>>();

    public T get(final int x, final int y, final int z) {
        if (elements.size() > x) {
            final List<List<T>> rowx = elements.get(x);
            if (rowx.size() > y) {
                final List<T> rowy = rowx.get(y);
                if (rowy.size() > z) {
                    return rowy.get(z);
                }
            }
        }
        return null;
    }
} 
  

Вы даже можете сделать это в одной строке, если не беспокоитесь о удобочитаемости:

 public T get(final int x, final int y, final int z) {
    return (elements.size() > x amp;amp; elements.get(x).size() > y amp;amp; elements.get(x).get(y).size() > z ? elements.get(x).get(y).get(z) : null);
}
  

И вам нужны методы put, которые при необходимости создают строки (как список массивов).

Ответ №2:

Из вашего вопроса не сразу понятно, что вы подразумеваете под максимальным размером матрицы. Всегда ли он трехмерный или может быть N-мерным на основе ввода пользователя?

Предполагая, что он трехмерный, является ли он регулярным? Является ли каждая матрица [i, j], [i, k] и [j, k] такой же, как и все остальные?

Если это так, вы могли бы предположительно смоделировать структуру как единый плоский список с двумя переменными — одна указывает длину строки на одном уровне матрицы, а другая указывает длину сетки в трехмерной структуре. Целочисленное деление даст вам трехмерное расположение в структуре:

учитывая idx n, длину строки k и базовый размер K:

n/K дает вам уровень и (n%K)/k дает вам строку на этом уровне. ((n%K))%k должен дать вам индекс внутри строки, если я не ошибаюсь.

Оберните это в класс, который заключает в себе эту логику, и вы можете рассматривать его как трехмерную структуру извне.

Ответ №3:

Как насчет ArrayList<Point[]> ? Вы можете даже подумать о реализации AbstractList для создания собственного списка (даже если вы используете ArrayList внутренне) и завершить создание Point массива…