2009-04-10 14 views
21

In realtà ho un paio di domande.Metodo Java: ricerca di oggetti nell'elenco di array dati un valore di attributo noto

ho una classe di Cane con i seguenti campi di esemplare:

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

Ho anche una classe Archivio che può istanziare Cane e mettere gli oggetti cane in un ArrayList.

Sto provando a scrivere un metodo in Archivio che accetta un numero intero come ID e controlla l'ArrayList e restituisce l'oggetto che contiene quell'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 

Esistono due problemi con questo metodo (gli altri metodi che utilizzo il lavoro). Prima di tutto non funziona, e non riesco a capire perché. Sto seguendo il ciclo (potenzialmente) di tutti gli oggetti nell'array, per poi dopo che il ciclo è finito, controllando se il ciclo è finito perché ha finito gli oggetti da cercare, o perché ha trovato un oggetto con l'ID dato . In secondo luogo, sembra un processo che richiede molto tempo. C'è un modo per velocizzare questo?

+0

come vengono getSize() e al definiti? – cobbal

risposta

16

A while si applica all'espressione o al blocco dopo while.

non avete un blocco, così il vostro mentre termina con l'espressione dog=al.get(i);

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

Tutto dopo che accade solo una volta.

Non c'è motivo di inventare un cane, visto che non usi mai il cane che hai inventato; assegni immediatamente un cane dall'array al riferimento del tuo cane.

E se è necessario ottenere un valore per una chiave, è necessario utilizzare una mappa, non una matrice.

Modifica: questo è stato donwmodded perché ??

Commento di OP:

Una ulteriore domanda per quanto riguarda il non dover fare una nuova istanza di un cane. Se estraggo solo copie degli oggetti dall'elenco di array, come posso estrarlo dall'elenco di array senza avere un oggetto in cui l'ho inserito? Ho notato anche che non ho usato il ciclo while.

Un riferimento Java e l'oggetto a cui si riferisce sono cose diverse. Sono molto simili a un riferimento e un oggetto C++, sebbene un riferimento Java possa essere ridefinito come un puntatore C++.

Il risultato è che Dog dog; o Dog dog = null fornisce un riferimento che punta a nessun oggetto. new Dog()crea un oggetto che può essere indirizzato.

In seguito con un dog = al.get(i) significa che il riferimento ora punta al riferimento cane restituito da al.get(i). Comprendere, in Java, gli oggetti non vengono mai restituiti, solo i riferimenti agli oggetti (che sono gli indirizzi dell'oggetto in memoria).

Il puntatore/riferimento/indirizzo del Cane di cui si è eseguito il nuovo aggiornamento è ora perso, poiché non vi è alcun codice, in quanto il referente è stato sostituito con il referente ottenuto da al.get(). Alla fine il garbage collector di Java distruggerà quell'oggetto; in C++ avresti "filtrato" la memoria.

Il risultato è che è necessario creare una variabile che può riferirsi a un cane; non è necessario creare un cane con new.

(In realtà non è necessario creare un riferimento, poiché ciò che si dovrebbe fare è restituire ciò che restituisce una Mappa dalla sua funzione get() .Se la Mappa non è parametrizzata su Cane, come questa : Map<Dog>, quindi è necessario trasmettere il ritorno da get, ma non è necessario un riferimento: return (Dog) map.get(id); o se la mappa è parametrizzata, return map.get(id). E quella riga è tutta la tua funzione, e sarà più veloce di iterando un array per la maggior parte dei casi.)

+0

Non penso che questa sia la risposta che sta cercando. Hai ragione sul fatto che il circuito non faccia quello che dovrebbe, ma non è questo il punto. E davvero non capisco cosa intendi per "novità" (presumo tu intenda la creazione di una nuova istanza), che lui non vuole nemmeno o non deve fare. – Jorn

+0

+1 per il consiglio Mappa. –

+0

Per quanto riguarda i commenti di Jorn ... direi che questa è la risposta che sta cercando. L'autore ha detto che non funziona, tpdi spiega perché non funziona. Il tuo commento sulla creazione della nuova istanza di cane è sconcertante. tpdi sta spiegando che non è necessario proprio come stai dicendo –

13

È necessario scorrere l'intero array, non è possibile modificarlo. È tuttavia possibile farlo un po 'più facile

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

o senza il nuovo ciclo for

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

Non è necessario scorrere l'elenco. – Jon

+0

Jon ha ragione, ma +1 comunque per dare la soluzione migliore/più pulita che usi ancora una lista (e non una mappa). –

+0

Devi ancora scorrere l'elenco per creare la mappa in primo luogo. Che sia più efficiente dipende da diversi fattori, tra cui la frequenza con cui la lista cambia e la frequenza con cui è necessario effettuare la ricerca. – Jorn

16

Per migliorare le prestazioni del funzionamento, se si sta andando sempre a voler guardare gli oggetti da alcuni identificativo univoco, quindi potresti prendere in considerazione l'utilizzo di Map<Integer,Dog>. Ciò fornirà una ricerca costante per chiave. Puoi ancora scorrere gli oggetti stessi usando la mappa values().

un frammento di codice rapido per iniziare:

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

Questo aiuterà ad accelerare un po 'se si sta eseguendo molteplici ricerche della stessa natura della lista. Se stai facendo solo la ricerca, allora dovrai sostenere lo stesso ciclo di overhead a prescindere.

1

Mi interessava vedere che il poster originale utilizzava uno stile che evitava le prime uscite. Entrata singola; Single Exit (SESE) è uno stile interessante che non ho davvero esplorato. È tardi e ho una bottiglia di sidro, quindi ho scritto una soluzione (non testata) senza un'uscita anticipata.

Avrei dovuto usare un iteratore. Sfortunatamente lo java.util.Iterator ha un effetto collaterale nel metodo get. (Non mi piace il design Iterator grazie alle sue ramificazioni eccezioni.)

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 la duplicazione del i!=dogs.length() espressione (avrebbe potuto scegliere dogs.get(i).getID()!=id).

43

Supponendo di aver scritto correttamente un metodo per Cane equo che si confronta in base all'ID del cane, il modo più semplice e semplice per restituire un elemento nell'elenco è il seguente.

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

Questo è meno intensivo di prestazioni che altri approcci qui. In questo caso non è necessario un ciclo. Spero che questo ti aiuti.

P.S È possibile utilizzare Apache Commons Lang per scrivere un semplice metodo equals per il cane come segue:

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

Se dovete ottenere un attributo che non è l'ID. Vorrei usare 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

Ho risolto questo using java 8 lambda

int dogId = 2; 

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