Java ArrayList добавить элемент за пределами текущего размера - PullRequest
7 голосов
/ 19 января 2012

Хотите знать, есть ли эффективный способ добавить элемент в ArrayList Java на большую позицию, чем его текущий размер:

Сценарий:

   ArrayList<Item> items = new ArrayList<Item>;
   ... let's say I add three elements

Теперь я хотел бы добавитьэлемент в позиции 10 (оставляя элементы с 3 по 10 равными нулю)

  items.add(10,newItem);  // item.size() == 3 

Есть ли эффективный способ изменения размера / заполнения ArrayList нулями?

Реализация Java делает поле размера приватным: -(..

Ответы [ 10 ]

6 голосов
/ 19 января 2012

imho, лучшее, что вы можете сделать, это items.addAll(Collections.nCopies(6, null)) и надеяться, что ArrayList реализует некоторое поведение для внутреннего закрепления этого

2 голосов
/ 19 января 2012

Как насчет этого?

ArrayList<Item> items = new ArrayList<Item>();

items.add(new Item(0));
items.add(new Item(1));
items.add(new Item(2));

items.addAll(Collections.<Item>nCopies(7, null));
items.add(10,new Item(10));

System.out.println(items);

отпечатки

[0, 1, 2, null, null, null, null, null, null, null, 10]
1 голос
/ 20 мая 2019

Это старый вопрос, но теперь вы можете использовать SparseArray как (почти) прямую замену для ArrayList.Он допускает несмежные значения целочисленных ключей и возвращает ноль, если значение не было установлено для ключа.С точки зрения производительности он был разработан точно для ваших нужд.Вместо add вы используете append, что более наглядно в том смысле, что вы добавляете в конец значения ключа max, даже если есть пробелы.Вы также можете set выбрать любое значение ключа, даже если оно превышает максимальное значение.

1 голос
/ 19 января 2012

Вместо этого используйте TreeMap.Вот простой пример проверки потребления памяти.Запустите первый и второй тест отдельно и используйте jvisualvm для проверки размера кучи.Не забывайте выполнять GC несколько раз.

    public class Test {


            public static void main(String[] args) throws InterruptedException {
                String s = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque metus.";


                //Test 1
                ArrayList<String> l = new ArrayList<String>();

                for (int i = 0; i < 1000000; i++) {
                    l.add(s + " " + i);
                    l.addAll(Collections.nCopies(i % 10, (String)null)); //Add some nulls
                }
                //Heap is > 5MB

                //Test 2 uncomment and comment test 1
    //          SortedMap<Integer, String> map = new TreeMap<Integer, String>();
    //          for (int i = 0; i < 1000000; i++) {
    //              map.put(i,s + " " + i);
    //          }
                //Heap is < 5MB

                Thread.sleep(100000);

            }
    }

Похоже, версия TreeMap потребляет меньше памяти, чем версия ArrayList.Проверь себя.

0 голосов
/ 20 января 2012

@ icCube - вы сказали, что этот список должен быть заполнен примерно на 90%. Моя идея для этого решения:

  • Если вы точно знаете размер цели - используйте обычный массив
  • Если вам известен размер цели - используйте ArrayList с начальной емкостью, максимально приближенной к целевому размеру. Поставьте нули с l.addAll(Collections.nCopies(n, (String)null));, как говорили люди.
  • Если вы не знаете размер цели - ваш ArrayList будет многократно изменен. Изменение размера означает копирование всего базового массива (он использует Arrays.copyOf). Вы можете представить, что произойдет, если массив будет скопирован - у GC много работы. Тогда используйте TreeMap.
0 голосов
/ 19 января 2012

Если память и индекс так важны, используйте обычный массив.

Когда дело доходит до малого использования System.arraycopy , то есть способ, которым ArrayList делает его внутренним.

-

Даже если вы используете ArrayList и имеете миллион объектов, рекомендуется использовать ArrayList (int initialCapacity) -Constructor, чтобы избежать большого количества операций копирования

0 голосов
/ 19 января 2012

Нет, вы не можете этого сделать, но если вы хотите это сделать, то добавьте пустой объект в оставшийся индекс, например ..

    ArrayList<Object> items = new ArrayList<Object>();
    items.add(new Object());
    items.add(new Object());
    items.add(new Object());
    items.add(3,new Object());
0 голосов
/ 19 января 2012

Я бы рассмотрел использование SortedMap вместо списка здесь. Это позволит индексам не существовать:

SorteMap<Integer, Item> myMap = new TreeMap<Integer, Map>();
int i=0;
myMap.put(i++, first);
myMap.put(i++, second);
myMap.put(i++, third);
myMap.put(10, other);

Если карта действительно не будет работать, как вы заявили. Затем я бы предложил создать Decorator для ArrayList. В методе вставки добавьте нули, чтобы заполнить пустые места. Я бы предложил использовать ForwardingList в Guava для облегчения создания класса. Таким образом, вам нужно будет реализовать только один метод.

0 голосов
/ 19 января 2012

Нет, вы не можете:

http://docs.oracle.com/javase/6/docs/api/java/util/ArrayList.html#add(int, E)

Броски: IndexOutOfBoundsException - если индекс находится вне диапазона (индекс <0 || индекс> размер ())

0 голосов
/ 19 января 2012

Использовать конструктор ArrayList(int initialCapacity). Таким образом, вы можете установить начальную емкость.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...