2013-08-27 7 views
6

Ich habe ein kurzes Beispiel für mein Problem erstellt. Ich erstelle eine Liste von Objekten anonym und füge sie zu einem ArrayList hinzu. Sobald Artikel in der ArrayList sind, komme ich später zurück und füge weitere Informationen zu jedem Objekt in der Liste hinzu. Gibt es eine Möglichkeit, ein bestimmtes Objekt aus der Liste zu extrahieren, wenn Sie seinen Index nicht kennen?Erhalten Sie bestimmte Objekte von ArrayList, wenn Objekte anonym hinzugefügt wurden?

Ich kenne nur den 'Namen' des Objekts, aber Sie können keine list.get(ObjectName) oder irgendetwas tun. Was ist der empfohlene Weg, damit umzugehen? Ich möchte nicht jedes Mal die gesamte Liste durchlaufen, wenn ich ein bestimmtes Objekt abrufen möchte.

public class TestCode{ 

    public static void main (String args []) { 
     Cave cave = new Cave(); 

     // Loop adds several Parties to the cave's party list 
     cave.parties.add(new Party("FirstParty")); // all anonymously added 
     cave.parties.add(new Party("SecondParty")); 
     cave.parties.add(new Party("ThirdParty")); 

     // How do I go about setting the 'index' value of SecondParty for example? 
    } 
} 

class Cave { 
    ArrayList<Party> parties = new ArrayList<Party>(); 
} 

class Party extends CaveElement{ 
    int index; 

    public Party(String n){ 
     name = n; 
    } 

    // getter and setter methods 

    public String toString() { 
     return name; 
    } 
} 


class CaveElement { 
    String name = ""; 
    int index = 0; 

    public String toString() { 
     return name + "" + index; 
    } 
} 
+0

Müssen Sie eine Liste verwenden? – smk

Antwort

11

Bei der Verwendung von List verwenden können, gibt es keine Möglichkeit, „Lookup“ ein Wert ohne Iteration durch es ...

Zum Beispiel ...

Cave cave = new Cave(); 

// Loop adds several Parties to the cave's party list 
cave.parties.add(new Party("FirstParty")); // all anonymously added 
cave.parties.add(new Party("SecondParty")); 
cave.parties.add(new Party("ThirdParty")); 

for (Party p : cave.parties) { 
    if (p.name.equals("SecondParty") { 
     p.index = ...; 
     break; 
    } 
} 

Nun, das wird Zeit brauchen. Wenn sich das Element, nach dem Sie suchen, am Ende der Liste befindet, müssen Sie bis zum Ende der Liste iterieren, bevor Sie eine Übereinstimmung finden.

Es könnte besser sein, ein Map irgendeiner Art zu verwenden ...

Also, wenn wir Cave aktualisieren aussehen ...

class Cave { 
    Map<String, Party> parties = new HashMap<String, Party>(25); 
} 

Wir mögen etwas tun könnte ...

Cave cave = new Cave(); 

// Loop adds several Parties to the cave's party list 
cave.parties.put("FirstParty", new Party("FirstParty")); // all anonymously added 
cave.parties.put("SecondParty", new Party("SecondParty")); 
cave.parties.put("ThirdParty", new Party("ThirdParty")); 

if (cave.parties.containsKey("SecondParty")) { 
    cave.parties.get("SecondParty").index = ... 
} 
Statt

...

Letztlich wird dies alles hängen davon ab, was es ist, das du erreichen möchtest ...

+1

Ich glaube, das ist die hilfreichste Antwort. Ich werde nicht in der Lage sein, eine Karte zu verwenden, gibt es ein bisschen mehr zu diesem Puzzle als ich für diese Fragen für die Ein kleines Dankeschön für die Antwort: – leigero

+1

@leigero Wenn Sie das Beste aus beiden Welten möchten, können Sie eine 'HashMap' verwenden, um die Zuordnung von' name' -> index zu speichern. –

+0

Auch wenn Sie brauchen Die Funktionalität von List aus anderen Gründen, ist es besser, dies als 'LinkedHashMap' hinter den Kulissen auszuführen und es nach Bedarf in List zu konvertieren. Maps sind viel effizienter – StormeHawke

4

List.indexOf() finden Sie, was Sie wollen, vorausgesetzt, Sie wissen genau, was Sie nach, und unter der Voraussetzung, dass die equals() Verfahren für Party ist gut definiert. Diese

Party searchCandidate = new Party("FirstParty"); 
int index = cave.parties.indexOf(searchCandidate); 

ist es interessant - Subklassen sollten nicht die privaten Eigenschaften ihrer Eltern werden untersuchen, so dass wir equals() in der übergeordneten Klasse definieren.

@Override 
public boolean equals(Object o) { 
    if (this == o) { 
     return true; 
    } 
    if (!(o instanceof CaveElement)) { 
     return false; 
    } 

    CaveElement that = (CaveElement) o; 

    if (index != that.index) { 
     return false; 
    } 
    if (name != null ? !name.equals(that.name) : that.name != null) { 
     return false; 
    } 

    return true; 
} 

Es ist auch ratsam hashCode außer Kraft zu setzen, wenn Sie equals außer Kraft setzen - der allgemeine Vertrag für hashCode schreiben vor, dass, wenn x.equals(y), dann x.hashCode() == y.hashCode().

@Override 
public int hashCode() { 
    int result = name != null ? name.hashCode() : 0; 
    result = 31 * result + index; 
    return result; 
} 
+0

Ja, du hattest Recht, mein Schlechter. Ein langer Tag: P –

5

Wenn Sie Objekte Nachschlag wollen basierend auf ihren String Namen, das ist ein Lehrbuchfall für eine Map ist, sagen wir ein HashMap. Du könntest eine verwenden und später in eine List oder Array umwandeln (Chris hat das in den Kommentaren unten schön behandelt).

weil Sie auf die Elemente in der Reihenfolge zugreifen können, in der Sie sie einfügen, wenn Sie dies tun möchten. Ansonsten wird HashMap oder TreeMap tun.

Sie könnten dies mit List arbeiten, wie die anderen vorschlagen, aber das fühlt sich Hacky zu mir .. und das wird auf kurze und lange Sicht sauberer sein.

Wenn Sie eine Liste für das Objekt verwenden MÜSSEN, könnten Sie immer noch eine Map des Objektnamens auf den Index im Array speichern. Dies ist ein bisschen hässlicher, aber Sie erhalten fast die gleiche Leistung wie eine einfache Map.

+2

Insbesondere können Sie 'map.values ​​(). ToArray (new Party [0])' verwenden, um in ein Array zu dumpen, und Sie können 'new ArrayList verwenden (map.values ​​()) 'in eine Liste ablegen. –

+1

Von all den 5 oder 6 Antworten, die ich bisher gesehen habe, mag ich deine am besten. Es hat O (1) Lookup und behält weiterhin die Reihenfolge der Anzeigen. –

+0

@ ChrisJester-Young yup danke, das ist, warum ich vorschlagen 'LinkedHashMap', sollte ich explizit machen –

0

Ich würde vorschlagen, überschreiben die equals(Object) Ihrer Party Klasse. Es könnte wie folgt aussehen:

public boolean equals(Object o){ 
    if(o == null) 
     return false; 
    if(o instanceof String) 
     return name.equalsIgnoreCase((String)o); 
    else if(o instanceof Party) 
     return equals(((Party)o).name); 
    return false; 
} 

Nachdem Sie das tun, Sie die indexOf(Object) Methode verwenden, um den Index der Partei durch seinen Namen angegeben abzurufen, wie unten dargestellt:

int index = cave.parties.indexOf("SecondParty"); 

Würde wieder der Index der Party mit dem Namen SecondParty.

Hinweis: Dies funktioniert nur, weil Sie die equals(Object) Methode überschreiben.

+0

Ich würde auch vorschlagen, dass es eine Verletzung von "equals" Vertrag ist, aber das ist nur MHO: P – MadProgrammer

+0

@MadProgrammer Eh, scheint aber ziemlich bequem zu sein: P –

+1

Bequem vielleicht, aber was passiert, wenn Sie zwei 'Party' Objekte benannt haben gleich, aber die Indizes sind unterschiedlich. Der Vertrag ist jetzt gebrochen;) – MadProgrammer

2

Sie könnten list.indexOf(Object) Bug in aller Ehrlichkeit verwenden, was Sie beschreiben klingt klingt wie Sie besser wäre mit einem Map.

Try this:

Map<String, Object> mapOfObjects = new HashMap<String, Object>(); 
mapOfObjects.put("objectName", object); 

dann später, wenn Sie das Objekt abrufen möchten, verwenden Sie

mapOfObjects.get("objectName"); 

Sie kennen den Namen des Objekts Unter der Voraussetzung tun, wie Sie erwähnt, wird dies sowohl sauberer sein und wird Darüber hinaus haben Sie eine schnellere Leistung, insbesondere wenn die Karte eine große Anzahl von Objekten enthält.

Wenn Sie die Objekte in der Map brauchen, um zu bleiben, Sie

Map<String, Object> mapOfObjects = new LinkedHashMap<String, Object>(); 

statt

1

Gemäß deiner Frageanforderung möchte ich vorschlagen, dass Karte dein Problem sehr effizient und ohne irgendeinen Ärger löst.

In Map können Sie den Namen als Schlüssel und Ihr Originalobjekt als Wert angeben.

Map<String,Cave> myMap=new HashMap<String,Cave>(); 
0

Sie könnten einfach eine Methode erstellen, um das Objekt anhand seines Namens abzurufen.

public Party getPartyByName(String name) { 
    for(Party party : parties) { 
     if(name.equalsIgnoreCase(party.name)) { 
      return party; 
     } 
    } 
    return null; 
} 
Verwandte Themen