2012-09-05 36 views
7

Estoy tratando de resolver el siguiente problema:
Comenzando con una colección A, quiero pasar algún tipo de 'vista' en esa colección (digamos colección B) a un método determinado. La vista B no contiene necesariamente todos los elementos de la colección original A. Si en este método los objetos se agregan o eliminan de la vista (colección B), estos cambios también deberían reflejarse en la colección original A también.Vista modificable de Java en la colección

Por ejemplo (pseudo-código): situación

  1. de inicio:

    Collection A = {1, 2, 3}; 
    View-on-collection B = {1, 2}; 
    
  2. Método de llamada: situación

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

    Collection A = {1, 3, 4}; 
    

¿Alguien sabe una buena solución a este problema?

+1

¿Y si lo hace 'b.Retire (3);' 'da 3' es sólo en A? –

+0

Hubiera dicho 'subList', pero eso no hace exactamente lo que quiere (la vista nunca cambia de tamaño, incluso si le agrega cosas). –

+1

@JoachimSauer: la vista puede cambiar de tamaño con 'subList()'. – Keppil

Respuesta

-2

Siempre se puede tener dos colecciones diferentes, una colección A y B. una colección

Entonces, cada vez que ha añadido algo a B, deberá añadir a A, y cada vez eliminado algo de B también quitaría desde A.

Al eliminar de A, debe comprobar si B contiene o no el objeto que desea eliminar y, de ser así, debe eliminarlo.

Sin embargo, al agregar a A, no tocaría B.

Esto podría ser menos eficiente que el espacio de una solución óptima, pero no va a cambiar complejidad del tiempo (excepto quizás el traslado de A.)

+0

¿Por qué tengo dos downvotes? Mi respuesta funciona bien. – eboix

+1

No lo rechacé, pero creo que no responde la pregunta. Usar dos colecciones no relacionadas no es una vista. El punto es, probablemente, que las dos colecciones se utilizarán en partes completamente diferentes del código, por lo que una sincronización manual no será posible. – lbalazscs

+0

@lbalazscs Pero el punto es que usted hace una nueva Colección que, en su interior, funciona así. No estoy proponiendo una sincronización manual. Solo digo que en el método add method/remove hace lo que dije en mi respuesta. – eboix

0

Jacarta marco de las colecciones tiene dicha funcionalidad. Pero este marco no es compatible con los genéricos. Eche un vistazo en Google Guava. Creo que también deberían ser compatibles con esa funcionalidad.

4

Una forma es utilizar 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);   
} 

Otra forma más general sería a través de guayabas Collections2.filter(), que permite definir un predicado para controlar qué objetos deben estar en la 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); 

} 

Ambos ejemplos imprimen

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

@Downvoter: ¿Me importa explicarme? – Keppil

+1

Sí, también encontré algo así, pero el problema es que SubList no es lo suficientemente flexible para nosotros: es posible que deseemos conservar algunos elementos que están en lugares aleatorios en la lista original, p. en la primera y la tercera posición, creo que no llegamos allí con subList. – Ward

+0

para dejar las cosas claras, yo no era el que menospreciaba. – Ward

0

Puede ampliar AbstractList (o cualquier tipo de colección abstracta que esté usando)

En esta abstracción, puede tomar la colección fuente en el constructor y mantener una referencia a ella y los puntos de inicio y fin de la vista del lista original

Anule los métodos de agregar/eliminar/configurar para que esas acciones también se realicen también en la colección fuente.

es decir

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 

}

El ListView efectivamente debe ser un Proxy a la lista original.

Alternativamente, y con un poco más de trabajo, se puede implementar la interfaz Collection o List para que se trabaja directamente en la lista original de una manera similar

entonces usted puede llamar a su método o pasar el ListView alrededor mientras tendrías una colección normal

decir

public void doSomeWork(Collection<String> collection); 

... 

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

¿Por qué se ha votado negativamente, es una solución efectiva y transparente al problema? –

+0

Lo mismo aquí. El mío también fue votado negativamente. Alguien probablemente publicó una nueva respuesta, vio a todos los demás, y quería que su respuesta estuviera arriba ... – eboix

Cuestiones relacionadas