Двумерный массив списков - PullRequest
2 голосов
/ 18 июля 2011

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

Должен ли я использовать что-то вроде

    ArrayList[][] foo = new ArrayList[4][4];

или

    ArrayList<SomeClass>[][] foo = new ArrayList[4][4];

и инициализировать каждый элемент с правильным типом в a дляloop or

    ArrayList<ArrayList<ArrayList<SomeClass>>> foo = ArrayList<ArrayList<ArrayList<SomeClass>>>();

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

РЕДАКТИРОВАТЬ: Получил несколько хороших ответов на мой вопрос, даже если он был немного неясным.Но это было в основном, как составить таблицу списков.Создание собственного класса для обработки строк / столбцов сделало его намного проще.

Ответы [ 4 ]

5 голосов
/ 18 июля 2011

Исправьте первый метод следующим образом:

List [] [] foo = new ArrayList [4] [4];

Второй метод не тот, который вам нужен.Вы пытаетесь создать 4-х мерный массив вместо 2-х мерного массива 4 * 4 элемента.

Кроме того, я хотел бы дать вам совет: никогда не используйте конкретный класс слева от назначения, т. Е. ArrayList list = .... Используйте List list = ...

И избегайте использования слишком сложных структур данных.Двухмерный массив списков слишком сложен.Создайте свой собственный класс, который инкапсулирует некоторую функциональность, а затем создайте коллекцию / массив (лучше одномерный) объектов вашего класса.

1 голос
/ 18 июля 2011

Вот пример для матрицы 2x2 с явной инициализацией.

List<MyClass>[][] matr = new List<MyClass>[][] {
    new List<MyClass&gt { new ArrayList<MyClass>(), new ArrayList<MyClass>() },
    new List<MyClass&gt { new ArrayList<MyClass>(), new ArrayList<MyClass>() }
}
0 голосов
/ 18 июля 2011
    public static class Grid<T> {

    public interface TFactory<T> {

        T create();
    }
    private T[] data;
    private int d1;
    private int d2;

    public Grid(int d1,
            int d2,
            Class<T> clazz,
            TFactory<T> fac) {
        this.d1 = d1;
        this.d2 = d2;
        data = (T[]) Array.newInstance(clazz, d1 * d2);
        for (int i = 0; i < data.length; i++) {
            data[i] = fac.create();
        }
    }

    public T get(int c1,
            int c2) {
        return data[c1 * d2 + c2];
    }
}

public static class ArrayListFactory<X> implements Grid.TFactory<ArrayList<X>> {

    public ArrayList<X> create() {
        return new ArrayList();
    }
}

public static void main(String[] args) throws RTXException, ParseException {
    // cannot use new new ArrayList<String>[4][4];, because of generic array creation error
    List<String>[][] a2d = new ArrayList[4][4];
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            a2d[i][j] = new ArrayList<String>();
        }
    }
    Grid g = new Grid(4, 4, ArrayList.class, new ArrayListFactory<String>());
}

Вот два подхода.Во-первых, это то, что вы просили, во-вторых, инкапсулированная версия (с 2d-массивом, преобразованным в 1d-массив для облегчения внутренних манипуляций).

Как было сказано ранее, вы должны как можно больше объявлять переменные как интерфейсы (но не более).).Это означает, что если все, что вы хотите сказать, это List, и он не ожидает, что кто-то будет вести себя по-другому в зависимости от конкретной реализации, просто используйте List, а не ArrayList в качестве типа переменной.Но если вы используете, например.LinkedSet может быть хорошей идеей использовать LinkedSet в качестве типа переменной (и в качестве возвращаемого значения функций), если вы хотите «пообещать», что он перечисляет все элементы быстро и в порядке вставки.Если вы используете Set, пользователь этого не должен зависеть от какого-либо конкретного порядка итерации.

btw.остерегайтесь явной инициализации.Это хороший синтаксис, но он создает анонимный внутренний класс и может привести к непреднамеренному сохранению родительского класса.Но если вы знаете, что делаете, и что это невозможно (без внешних указаний), в этом нет ничего плохого.

0 голосов
/ 18 июля 2011

Как уже сказал Алекс, наличие двумерного массива списков довольно сложно и его легко ошибиться или использовать неправильно.

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

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

class Cell {
  private List<SomeClass> content = new ArrayList<SomeClass>();
  ...
}

Cell[][] matrix = new Cell[4][4];  //don't forget to initialize each cell
...