2012-01-19 10 views
7

Ti chiedi se ci sia un modo efficace per aggiungere un elemento a ArrayList di Java in una posizione più grande rispetto alle dimensioni attuali:Java ArrayList aggiungere voce fuori dimensione attuale

Scenario:

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

Ora vorrei per aggiungere un elemento alla posizione 10 (lasciando gli articoli da 3 a 10 null)

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

c'è un modo efficiente ridimensionamento/riempire un ArrayList con nulls? ..

implementazione di Java rende campo dimensione :-(privato ..

+0

Probabilmente dovresti usare HashMap o SortedMap. –

+0

Ok, l'uso di una mappa non è una soluzione per la memoria, sappiamo che alla fine la struttura è piena -> TIntObjectHashMap (trove) forse – ic3

+0

Una HashMap non supporta l'ordine. Una SortedMap è un'opzione migliore. –

risposta

6

imho la cosa migliore che puoi fare è items.addAll(Collections.nCopies(6, null)) e Spero che ArrayList implementa alcuni comportamenti per fissarlo internamente

+0

Questo è bello ma un po' spaventoso dal punto di vista delle prestazioni – ic3

+0

bene nCopies produce solo un elenco-Wrapper per un array e in questo modo il tuo ArrayList è in grado di usare System .arraycopy per compilare i valori nulli a seconda di quanto sia intelligente implementato – Hachi

+1

addolcitore pubblico booleano (Raccolta c) { \t Oggetto [] a = c.toArray(); int numNew = a.length; \t ensureCapacity (size + numNew); // Incrementi modCount Sistema.arraycopy (a, 0, elementData, size, numNew); size + = numNew; \t return numNew! = 0; } – ic3

-2

Usa costruttore ArrayList(int initialCapacity) In questo modo è possibile impostare una capacità iniziale

+1

InitialCapacity non è la dimensione -> Eccezione nella discussione "main" java.lang.IndexOutOfBoundsException: Index: 9, Size: 0 – ic3

+0

Try : public static void main (String [] args) { ArrayList list = new ArrayList (10); list.add (9,3); } – ic3

0

Vorrei prendere in considerazione l'utilizzo di un SortedMap invece di un elenco qui. Ciò consentirà per gli indici di non esistere:

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); 

Se una mappa davvero non funzionerà, come hai affermato. Suggerirei quindi di creare un decoratore attorno a ArrayList. Nel metodo di inserimento, aggiungere null per riempire le posizioni vuote. Vorrei suggerire l'uso di Guava ForwardingList per facilitare la creazione della classe. In questo modo dovresti solo implementare un metodo.

+0

che non è un'opzione per raisons memoria ... – ic3

+0

Cosa c'è di sbagliato con la memoria qui? @ John B - correggi questo codice. –

+0

TreeMap con 1mio Object è grande. – ic3

0

No, non è possibile fare questo, Ma se si vuole fare questo, quindi aggiungere oggetto vuoto nel restante indice come ..

ArrayList<Object> items = new ArrayList<Object>(); 
    items.add(new Object()); 
    items.add(new Object()); 
    items.add(new Object()); 
    items.add(3,new Object()); 
+0

in realtà stavo lucking per qualcosa di un po 'più elegante :-) – ic3

2

Che ne dici di questo?

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); 

stampe

[0, 1, 2, null, null, null, null, null, null, null, 10] 
+0

Usa '10 - items.size' invece di' 7' come opzione più solida. –

0

Se la memoria e l'indice è così importante che utilizzano una matrice normale.

Quando diventa di uso ridotto System.arraycopy questo è il modo in cui ArrayList lo esegue internamente.

-

anche se si utilizza l'ArrayList e hanno un milione di oggetti, è consigliabile usare l'ArrayList (int initialCapacity) -Constructor per evitare un sacco di copia-operazioni

1

Usa TreeMap invece. Ecco un semplice esempio per controllare il consumo di memony. Esegui il primo e il secondo test separatamente e usa jvisualvm per controllare le dimensioni dell'heap. Ricorda di eseguire GC più volte.

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); 

      } 
    } 

Sembra TreeMap versione è ancora meno consumo di memoria rispetto alla versione ArrayList. Controllati.

+0

Peter, ArrayList è un array e poco altro. Com'è possibile che un array completo abbia più dimensioni di qualsiasi altra struttura? ... Penso che il vostro esempio ha un problema (ne sono certo) – ic3

+0

Stiamo parlando di una gamma completa .. – ic3

+0

La matrice è (s - stringa, null n-): snsnnsnnnsnnnnsnnnnns nnnnnnsnnnnnnns ... ecc C'è molto di memoria riservata per riferimenti ma impostata su null. TreeMap non ha questo problema. Come hai detto, è un array. Anche un array di 1 milione null costa ancora memoria. E 'tutto su come "densa" è la vostra lista. –

0

@ icCube- hai detto che l'elenco dovrebbe essere pieno al 90%. La mia idea per questa soluzione è:

  • Se si sa esattamente dimensione di destinazione - utilizzare array di pianura
  • Se siete a conoscenza di dimensione di destinazione - l'uso ArrayList con capacità iniziale il più vicino possibile alla dimensione di destinazione. Put nulls con l.addAll(Collections.nCopies(n, (String)null)); come dicevano le persone.
  • Se non si conosce la dimensione della destinazione, la tua ArrayList verrà ridimensionata molte volte. Ridimensionare significa copiare l'intera matrice sottostante (utilizza Arrays.copyOf). Puoi immaginare cosa succede se la matrice viene copiata - GC ha un sacco di lavoro. Usa TreeMap quindi.