2009-04-10 12 views
21

Tengo un par de preguntas en realidad.Método de Java: Encontrar objetos en la lista de arreglos dado un valor de atributo conocido

tengo una clase perro con los siguientes campos de instancia:

private int id; 
private int id_mother; 
private int id_father; 
private String name=""; 
private String owner=""; 
private String bDate=""; 

también tengo una clase Archivo que puede crear una instancia perro y poner objetos perro en un ArrayList.

Estoy tratando de escribir un método en Archivo que toma un número entero como ID y mira a través de ArrayList, y devuelve el objeto que contiene esa ID.

private Dog getDog(int id){ 
    Dog dog = new Dog(); 
    int length=getSize(); 
    int i=0; 

    dog=al.get(i); 
    i++; 

    while(dog.getId()!=id && i<length) 
     dog=al.get(i); 
     i++; 

    if(dog.getId()!=id) 
     dog=null; 
    return dog; 
}//end getDog 

Hay dos problemas con este método (los otros métodos que uso funcionan). En primer lugar, no funciona, y no puedo ver por qué. Estoy recorriendo (potencialmente) todos los objetos de la lista de arrays, para luego finalizar el ciclo, verificando si el ciclo finalizó porque se quedó sin objetos para buscar, o porque encontró un objeto con la ID proporcionada . En segundo lugar, parece un proceso inmensamente lento. ¿Hay alguna forma de acelerar esto?

+0

cómo se getSize() y Al definen? – cobbal

Respuesta

16

A while se aplica a la expresión o al bloque después del while.

usted no tiene un bloque, por lo que su tiempo termina con la expresión dog=al.get(i);

while(dog.getId()!=id && i<length) 
       dog=al.get(i); 

Todo después de eso sucede sólo una vez.

No hay ninguna razón para revivir un perro, ya que nunca usa el perro que descubrió; usted inmediatamente asigna un Perro de la matriz a su referencia de perro.

Y si necesita obtener un valor para una clave, debe usar un Mapa, no una Matriz.

Editar: esto no fue por qué?

Comentario de OP:

Una cuestión adicional, con respecto a no tener que hacer una nueva instancia de un perro. Si solo estoy sacando copias de los objetos de la lista de arreglos, ¿cómo puedo sacarlos de la lista de arreglos sin tener un objeto en el que los coloque? Me di cuenta también de que no encerré el loop while.

Una referencia de Java y el objeto al que hace referencia son cosas diferentes. Son muy parecidos a una referencia y objeto de C++, aunque una referencia de Java se puede volver a señalar como un puntero de C++.

El resultado es que Dog dog; o Dog dog = null le da una referencia que apunta a ningún objeto. new Dog()crea un objeto al que se puede apuntar.

Siguiendo que con dog = al.get(i) significa que la referencia ahora apunta a la referencia de perro devuelta por al.get(i). Entender, en Java, nunca se devuelven objetos, solo referencias a objetos (que son direcciones del objeto en la memoria).

El puntero/referencia/dirección del perro que acabas de actualizar ahora se ha perdido, ya que ningún código se refiere a él, ya que el referente fue reemplazado por el referente que obtienes de al.get(). Finalmente, el recolector de basura de Java destruirá ese objeto; en C++, habrías "filtrado" la memoria.

El resultado es que usted necesita crear una variable que se pueda referir a un perro; no es necesario crear un perro con new.

(En verdad no necesita crear una referencia, ya que lo que realmente debería hacer es devolver lo que devuelve un Mapa desde su función get(). Si el Mapa no está parametrizado en Perro, como este : Map<Dog>, luego tendrá que emitir el retorno desde get, pero no necesitará una referencia: return (Dog) map.get(id); o si el Mapa está parametrizado, return map.get(id). Y esa línea es toda su función, y será más rápido que iterando una matriz para la mayoría de los casos.)

+0

No creo que esta sea la respuesta que está buscando. Tiene razón sobre que el ciclo no está haciendo lo que debería, pero ese no es el punto. Y realmente no entiendo lo que quieres decir con respecto a la "actualización" (supongo que te refieres a crear una nueva instancia), lo que él ni siquiera quiere o necesita hacer. – Jorn

+0

+1 para el consejo de Mapa. –

+0

Con respecto a los comentarios de Jorn ... diría que esta es la respuesta que está buscando. El autor dijo que no funciona, tpdi explica por qué no funciona. Tu comentario sobre crear la nueva instancia de perro es desconcertante. tpdi está explicando que no es necesario, como dices –

13

Tiene que recorrer toda la matriz, no hay cambios. Sin embargo, puede hacerlo un poco más fácil

for (Dog dog : list) { 
    if (dog.getId() == id) { 
    return dog; //gotcha! 
    } 
} 
return null; // dog not found. 

o sin el nuevo ciclo for

for (int i = 0; i < list.size(); i++) { 
    if (list.get(i).getId() == id) { 
    return list.get(i); 
    } 
} 
+0

No es necesario recorrer la lista. – Jon

+0

Jon tiene razón, pero +1 de todos modos por dar la mejor/más limpia solución que todavía usa una lista (y no un mapa). –

+0

Todavía tiene que recorrer la lista para crear el mapa en primer lugar. Si eso es más eficiente o no depende de varios factores, incluida la frecuencia con la que cambia la lista y la frecuencia con la que se necesita la búsqueda. – Jorn

16

Para mejorar el rendimiento de la operación, si siempre va a querer para buscar objetos por algunos identificador único, entonces podría considerar usar un Map<Integer,Dog>. Esto proporcionará búsqueda de tiempo constante por clave. Todavía puede iterar sobre los objetos utilizando el mapa values().

Un fragmento de código rápido para que pueda empezar:

// Populate the map 
Map<Integer,Dog> dogs = new HashMap<Integer,Dog>(); 
for(Dog dog : /* dog source */) { 
    dogs.put(dog.getId(), dog); 
} 

// Perform a lookup 
Dog dog = dogs.get(id); 

Esto ayudará a acelerar las cosas un poco si usted está realizando múltiples operaciones de búsqueda de la misma naturaleza en la lista. Si solo hace una búsqueda, incurrirá en la misma sobrecarga del ciclo independientemente.

1

Me interesó ver que el cartel original usaba un estilo que evitaba las salidas anticipadas. Sola entrada; Single Exit (SESE) es un estilo interesante que realmente no exploré. Es tarde y tengo una botella de sidra, así que escribí una solución (no probada) sin una salida anticipada.

Debería haber usado un iterador. Desafortunadamente java.util.Iterator tiene un efecto secundario en el método get. (No me gusta el diseño Iterator debido a sus ramificaciones de excepción.)

private Dog findDog(int id) { 
    int i = 0; 
    for (; i!=dogs.length() && dogs.get(i).getID()!=id; ++i) { 
     ; 
    } 

    return i!=dogs.length() ? dogs.get(i) : null; 
} 

Nota de la duplicación de la expresión i!=dogs.length() (podría haber elegido dogs.get(i).getID()!=id).

43

Suponiendo que ha escrito correctamente un método equals para Perro que se compara con el ID del perro, la forma más fácil y sencilla de devolver un elemento en la lista es la siguiente.

if (dogList.contains(dog)) { 
    return dogList.get(dogList.indexOf(dog)); 
} 

Eso requiere menos rendimiento que otros enfoques aquí. No necesita un ciclo en este caso. Espero que esto ayude.

P.S Puede utilizar Apache Commons Lang escribir un simple método equals para el perro de la siguiente manera:

@Override 
public boolean equals(Object obj) {  
    EqualsBuilder builder = new EqualsBuilder().append(this.getId(), obj.getId());    
    return builder.isEquals(); 
} 
0

Si usted tiene que conseguir un atributo que no es el ID. Yo usaría CollectionUtils.

Dog someDog = new Dog(); 
Dog dog = CollectionUtils(dogList, new Predicate() { 

@Override 
public boolean evaluate(Object o) 
{ 
    Dog d = (Dog)o; 
    return someDog.getName().equals(d.getName()); 
} 
}); 
0

que resolvieron este usando Java 8 lambdas

int dogId = 2; 

return dogList.stream().filter(dog-> dogId == dog.getId()).collect(Collectors.toList()).get(0); 
Cuestiones relacionadas