Lista de no re-indexación con desfragmentación -- java campo con array campo con collections camp codereview Relacionados El problema

Non-re-indexing List with defragmentation


2
vote

problema

Español

Actualmente estoy codificando algo donde tengo objetos que toman una identificación y se almacenan en una lista. Para una fácil recuperación, la identificación del objeto es su índice en la lista. Sin embargo, eso significa que el objeto no se puede eliminar de la lista sin que todo se vaya al infierno, ya que la lista se volverá a indexar y, por lo tanto, no podré recuperar el objeto correcto de la lista conociendo su ID ya. < / p>

Tampoco quiso usar un mapa, ya que solo se ve feo y hace que una gran parte de mi código se vea más complicada de lo que debería.

Por lo tanto, intenté simplemente usar una lista, pero modificarla para poder obtener un índice que no cambie siempre y cuando el objeto esté vivo.

  @SuppressWarnings("serial") public class SafeIndexList<E> extends ArrayList<E> {      Stack<Integer> safeIndexes = new Stack<Integer>();      @Override     public E remove(int index){         if(this.size()-1 == index) return super.remove(index);         else {             E e = this.get(index);             this.set(index, null);             safeIndexes.push(index);             return e;         }     }      public int getSafeIndex(){         return safeIndexes.size() > 0 ? safeIndexes.pop() : size();     }  }   

¿Es este "bueno" o simplemente completo, lo siento por la redacción, la mierda?

Original en ingles

I'm currently coding something where I have Objects that take on an ID, and are stored in a List. For easy retrieval, the ID of the object is it's index in the list. However, that means that the object cannot be removed from the list without everything going to hell, since the list will be re-indexed and thus I won't be able to retrieve the right object from the list by knowing its ID anymore.

I also did not want to use a Map, since that just looks ugly and makes a big part of my code look more complicated than it should.

Thus, I tried to simply use a list, but modify it in order to be able to get an index that won't change as long as the object is alive.

@SuppressWarnings("serial") public class SafeIndexList<E> extends ArrayList<E> {      Stack<Integer> safeIndexes = new Stack<Integer>();      @Override     public E remove(int index){         if(this.size()-1 == index) return super.remove(index);         else {             E e = this.get(index);             this.set(index, null);             safeIndexes.push(index);             return e;         }     }      public int getSafeIndex(){         return safeIndexes.size() > 0 ? safeIndexes.pop() : size();     }  } 

Is this "good" or just complete, sorry for the wording, bullshit?

        
         
         

Lista de respuestas

2
 
vote
vote
La mejor respuesta
 

No está completo BS. Su caso de uso es algo sorprendente, y su desprecio por usar un mapa también es sorprendente, pero se le da, se queda con una pequeña opción que no sea una implementación completamente personalizada ... Pero, veamos los problemas que tiene actualmente. ...

Las personas deben hacer una operación de consulta antes de la consulta de ida y vuelta, deben llamar getSafeIndex() antes de configurar un nuevo valor.

Las personas no pueden usar todos los métodos disponibles para ellos. Por ejemplo, no pueden llamar:

  • clear() (consulte código )
  • add(int, obj) (consulte código )
  • ..... ninguno de los iteradores, o métodos relacionados con la corriente (foreach, etc.) porque devolverán los valores nulos mezclados en los lugares equivocados.
  • size() le mentirá.

... De hecho, los únicos métodos que se pueden usar de manera confiable son set(...) , 9988776655544335 y similares.

Extendiendo ArrayList parece introducir muchas formas de romper la integridad del código / datos.

Recomiendo la encapsulación en su lugar. De hecho, este es un "debate" común: herencia vs. composición / encapsulación (busque aquellos temas en Google).

En este caso, la composición / encapsulación eliminaría muchos de sus problemas y reduciría la clase a lo que necesita.

Subyacente de su clase Puede tener la lista de array y la pila, (excepto 9988776655544337 la clase está en desuso a favor de 9988777665544338 interfaces), pero se vería como:

  @SuppressWarnings("serial") public class SafeIndexList<E> {      List<E> data = new ArrayList<>();     Deque<Integer> safeIndexes = new ArrayDeque<>();      public E remove(int index){         if(index < data.size())             // check double-removes.             if (!safeIndexes.contains(index)) {                 safeIndexes.push(index);             }             return super.remove(index);         }         return null;     }      public int add(E value){         int idx = safeIndexes.isEmpty() ? data.size() : safeIndexes.pop();         data.set(idx, value);         return idx;     }  }   

Puede agregar métodos para otras características que necesita, según sea necesario. Nota, que después de resumir / encapsuló el mecanismo de almacenamiento de datos subyacentes, puede reemplazar fácilmente la matriz / deque con un mapa ahora, y no se dará cuenta.

Editar : Para agregar en el problema de constructor / índice combinado, una solución como esta puede ayudarlo, agregando el método:

  clear()0  

Ahora, puedes llamarlo con algo como:

  clear()1  

Los anteriores construyen el objeto interno con el índice, pero "interno" a la lista también. Alternativamente, puede devolver el objeto construido si tiene más sentido ...

  clear()2  
 

It's not complete BS. Your use-case is somewhat surprising, and your disregard for using a Map is also surprising, but given those, you're left with little option other than a completely custom implementation.... but, let's look at the issues you currently have...

People need to do a round-trip query-before-inserting operation - they need to call getSafeIndex() before setting a new value.

People can't use all the methods available to them. For example, they can't call:

  • clear() (See code)
  • add(int, obj) (See code)
  • ..... none of the iterator, or stream-related methods (foreach, etc.) because they will return null values mixed in the wrong places.
  • size() will lie to them.

... in fact, the only methods that can be used reliably are set(...), get(...), and similar ones.

Extending ArrayList seems to introduce a lot of ways to break the code/data integrity.

I recommend encapsulation instead. In fact, this is a common "debate": Inheritance vs. Composition/Encapsulation (search for those topics on google).

In this case, composition/encapsulation would remove a lot of your issues, and reduce the class to just what you need.

Underlying your class you could still have the ArrayList and Stack, (except Stack class is deprecated in favour of Deque interfaces) but it would look something like:

@SuppressWarnings("serial") public class SafeIndexList<E> {      List<E> data = new ArrayList<>();     Deque<Integer> safeIndexes = new ArrayDeque<>();      public E remove(int index){         if(index < data.size())             // check double-removes.             if (!safeIndexes.contains(index)) {                 safeIndexes.push(index);             }             return super.remove(index);         }         return null;     }      public int add(E value){         int idx = safeIndexes.isEmpty() ? data.size() : safeIndexes.pop();         data.set(idx, value);         return idx;     }  } 

You can add methods for other features you need, as needed. Note, that having abstracted/encapsulated the underlying data store mechanism, you can easily replace the array/deque with a Map now, and not notice.

Edit: to add in the combined constructor/index problem, a solution like this may help, adding the method:

    public int construct(IntFunction<E> factory) {         int idx = safeIndexes.isEmpty() ? data.size() : safeIndexes.pop();         data.set(idx, factory.apply(idx));         return idx;     } 

Now, you can call that with something like:

int id = mylist.construct(i -> new MyObject(..., i, ...)); 

The above constructs the inner object with the index, but "internal" to the list too. Alternatively, you can return the constructed object if that makes more sense....

MyObject obj = mylist.construct(i -> new MyObject(..., i, ...)); 
 
 
   
   
1
 
vote

Si desea asignar ID a objetos, entonces MAP es la opción correcta (HashMap como la implementación):

  clear()3  

No puedo imaginar que la solución basada en mapas sea más difícil de crear y mantener que el clear()4 ...

 

If you want to map IDs to Objects, then Map is the right choice (HashMap as the implementation):

Map<Integer, Object> objectMap = new HashMap<>(); 

I cannot imagine Map-based solution being harder to create and maintain than the SafeIndexList...

 
 

Relacionados problema

1  Visualización de datos trazados en orden serpentino  ( Displaying plotted data in serpentine order ) 
Tengo que mostrar un conjunto de: datos en orden serpentina. En un experimento hay replicación, gama y parcela. Las repeticiones contienen una parcela. U...

3  Definiendo la transposición en una colección de colecciones irregulares  ( Defining transpose on a collection of irregular collections ) 
Me pidieron que presentara mi solicitud de revisión de código en https: //stackoverflow.com/questions/10672046/defining-transpose-on-a-collection-of-irregula...

10  Más imitación de enumerable en VBA  ( More imitation of enumerable in vba ) 
Me inspiró en yo cómo se pregunta para ver qué tan lejos podría impulsar una imitación de . La clase enumerable de la red . Las nuevas funciones pueden ma...

3  Generando todos los subconjuntos de un conjunto dado  ( Generating all subsets of a given set ) 
Estoy aprendiendo marco de colecciones Java. ¿Puede alguien mirar este código para generando todos los subconjuntos de un conjunto dado y dígame algún probl...

48  Lista <T> Implementación para VB6 / VBA  ( Listt implementation for vb6 vba ) 
Recientemente, decidí que el 998877665555544330 no fue suficiente para mis necesidades, así que decidí implementar algo como C # 's List<T> . Aquí está la ...

7  Colecciones vacías en caché  ( Cached empty collections ) 
A menudo necesito devolver las colecciones vacías. Uno de esos días, escribí lo siguiente para devolver una instancia en caché: public static class Array<...

2  Eliminar la lista de archivos de otra lista de archivos por su nombre  ( Remove list of files from another list of files by their name ) 
En Groovy, tengo una lista de archivos A y también otra lista de archivos B. Quiero eliminar todos los archivos de A que tienen un nombre de archivo que tambi...

10  Clasificación de una colección  ( Sorting a collection ) 
relacionado con, pero no exactamente un seguimiento de esta pregunta . Después de solucionar algunos problemas descubiertos en la última revisión, agregué un...

11  LinkedHashMap como caché LRU  ( Linkedhashmap as lru cache ) 
Tengo una implementación simple para un caché LRU usando LinkedHashMap . Quiero que sea lo más genérico posible. Esto no es para uso de la producción, s...

3  Algoritmo de detección de intersección  ( Intersection detection algorithm ) 
Este es un algoritmo de detección de intersección que desarrollé como un método alternativo para el desarrollado para mis cursos. No publicaré algunas de las ...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos