2012-09-05 7 views
7

Sto cercando di risolvere il seguente problema:
A partire da una raccolta A, voglio passare una sorta di 'vista' su quella raccolta (ad esempio la raccolta B) ad un certo metodo. La vista B non contiene tutti gli elementi della collezione originale A. Se in questo metodo gli oggetti vengono aggiunti o rimossi dalla vista (raccolta B), anche queste modifiche dovrebbero riflettersi sulla raccolta originale A.Visualizzazione modificabile Java alla raccolta

Per esempio (pseudo-codice):

  1. Inizio situazione:

    Collection A = {1, 2, 3}; 
    View-on-collection B = {1, 2}; 
    
  2. chiamata di metodo: situazione

    someMethod(B) { 
        B.add(4); 
        B.remove(2); 
    } 
    
  3. fine:

    Collection A = {1, 3, 4}; 
    

Qualcuno sa una soluzione chiara a questo problema?

+1

Che cosa succede se si fa 'b.Togliere (3);' 'dato 3' è solo in A? –

+0

Avrei detto 'sottoclista', ma ciò non fa esattamente quello che vuoi (la vista sembra non cambiare mai le dimensioni, anche se aggiungi cose ad essa). –

+1

@JoachimSauer: la vista può cambiare dimensione con 'subList()'. – Keppil

risposta

-2

Si può sempre avere due diverse collezioni, una collezione A e una collezione B.

Poi, ogni volta che si è aggiunto qualcosa a B, si dovrebbe aggiungere a A, e ogni volta rimosso qualcosa B si potrebbe anche rimuovere da A.

Quando si rimuove da A si dovrebbe verificare se B contenesse l'oggetto da rimuovere e, in caso affermativo, lo si rimuovesse.

Tuttavia, quando si aggiunge a A, non si desidera toccare B.

Questo potrebbe essere meno spazio efficiente di una soluzione ottimale, ma non cambierà il tempo di complessità (ad eccezione forse assorbimenti dovuti A.)

+0

Perché ho due downvotes? La mia risposta funziona bene. – eboix

+1

Non l'ho sottovalutato, ma penso che non risponda alla domanda. L'utilizzo di due raccolte non correlate non è una vista. Il punto è probabilmente che le due raccolte verranno utilizzate in parti completamente diverse del codice, quindi una sincronizzazione manuale non sarà possibile. – lbalazscs

+0

@lbalazscs Ma il punto è che si crea una nuova Collezione che, all'interno, funziona così. Non sto proponendo una sincronizzazione manuale. Sto solo dicendo che nel metodo aggiungi/rimuovi metodo fai quello che ho detto nella mia risposta. – eboix

0

Jacarta collezioni quadro ha tale funzionalità. Ma questa struttura non supporta i farmaci generici. Dai un'occhiata a Google Guava. Credo che dovrebbero supportare anche questa funzionalità.

4

Un modo è quello di utilizzare List.sublist():

public static void main(String[] args) { 
    List<Integer> aList = new ArrayList<Integer>(Arrays.asList(1,2,3)); 
    List<Integer> view = aList.subList(0, 2); 

    view.add(new Integer(4)); 
    view.remove(new Integer(2)); 
    System.out.println("aList: " + aList); 
    System.out.println("view : " + view);   
} 

Un altro modo più generale sarebbe attraverso Guavas Collections2.filter(), che consente di definire un predicato per controllare quali oggetti devono essere nella vista:

public static void main(String[] args) { 

    List<Integer> aList = new ArrayList<Integer>(Arrays.asList(1,2,3)); 
    @SuppressWarnings("unchecked") 
    Collection<Integer> view = Collections2.filter(aList, new Predicate() { 
     public boolean apply(Object arg0) { 
      return ((Integer) arg0).intValue() % 3 != 0; 
     }}); 
    view.add(new Integer(4)); 
    view.remove(new Integer(2)); 
    System.out.println("aList: " + aList); 
    System.out.println("view : " + view); 

} 

Entrambi gli esempi stampa

aList: [1, 4, 3] 
view : [1, 4] 
+0

@Downvoter: attenzione a spiegare? – Keppil

+1

Sì, ho trovato anche qualcosa di simile, ma il problema è che la sottocartella non è abbastanza flessibile per noi: potremmo voler conservare alcuni elementi che si trovano in posizioni casuali nell'elenco originale, ad es. nella prima e nella terza posizione, penso che non ci arriveremo utilizzando la sottolista. – Ward

+0

per chiarire le cose, non ero il downvoter. – Ward

0

È possibile estendere AbstractList (o il tipo di raccolta mai usato in origine)

In questa astrazione, è possibile prendere la raccolta di origine nel costruttore e mantenere un riferimento ad esso e i punti di inizio e fine della vista del elenco originale

Sovrascrivere i metodi aggiungi/rimuovi/imposta in modo che tali azioni vengano eseguite anche sulla raccolta di origine.

cioè

class ListView<T> extends AbstractList<T> { 

    int start = 0; 
    int end = 0; 
    private Collection<T> original = null; 

    public ListView(List<T> original, int start, int end) { 
     this.original = original; 
     this.start = start; 
     this.end = end; 
     super.addAll(0, original.subList(start, end)); 
    } 

    // Any add/set/remove must also alter the original 

}

Il ListView in modo efficace dovrebbe essere una Proxy all'elenco originale.

In alternativa, e con un po 'più di lavoro, è possibile implementare l'interfaccia Collection o List in modo che si lavora direttamente sulla lista originale in un modo simile

È quindi possibile chiamare il metodo o passare il ListView intorno come avresti una collezione normale.

cioè

public void doSomeWork(Collection<String> collection); 

... 

object.doSomeWork(new ListView<String>(original, 0, 2)); 
+1

Perché è stato downvoted, è una soluzione efficace e trasparente al problema? –

+0

Lo stesso qui. Il mio è stato anche downvoted. Qualcuno probabilmente ha pubblicato una nuova risposta, ha visto tutti gli altri e voleva che la sua risposta fosse al top ...... – eboix

Problemi correlati