2016-05-26 14 views
0

Ich habe ein HashSet von benutzerdefinierten Objekten. Ich möchte ein Element aus dem Set entfernen, es modifizieren und es zurückstellen. Gibt es eine Möglichkeit, dies zu tun? Das Problem bei der Verwendung von Set.remove(Object o) ist, dass das von mir entfernte Element nicht zurückgegeben wird. HierJava: Ich habe ein Set von benutzerdefinierten Klassen. Wie kann man ein Element des Sets entfernen, modifizieren und wieder einfügen?

ist ein Beispiel dafür, was ich versuche zu tun:

import java.util.HashSet; 
import java.util.Set; 
import org.apache.commons.lang3.builder.EqualsBuilder; 
import org.apache.commons.lang3.builder.HashCodeBuilder; 

public class Planet { 
    private String name; 
    private Set<String> moons = new HashSet<String>(); 

    public void addMoon(String name) { 
     moons.add(name); 
    } 

    @Override 
    public boolean equals(Object obj) 
    { 
     if (obj == null) return false; 
     if (obj == this) return true; 
     if (obj.getClass() != getClass()) return false; 
     Planet rhs = (Planet) obj; 
     return new EqualsBuilder() 
       .append(getName(), rhs.getName()) 
       .isEquals(); 
    } 

    @Override 
    public int hashCode() 
    { 
     return new HashCodeBuilder(17,31). 
       append(getName()) 
       .toHashCode(); 
    } 

    public String getName() { return name; } 

    public void setName(String name) { this.name = name; } 

    public Set<String> getMoons() { return moons; } 


} 

Set<Planet> solarSystem = new HashSet<Planet>(); 

Planet addThisPlanet = new Planet(); 
addThisPlanet.setName("Jupiter"); 
addThisPlanet.addMoon("Titan"); 

if (solarSystem.contains(addThisPlanet)) { 
    Planet currentPlanet = // element of solarSystem that equals(addThisPlanet) 
    // remove currentPlanet from solarSystem 
    for(String moon: addThisPlanet.getMoons()) { 
     currentPlanet.addMoon(moon); 
    } 
    solarSystem.add(currentPlanet); 
} else { 
    solarSystem.add(addThisPlanet); 
} 

Hier ist, was ich tue, ist das Hinzufügen von Monden eins nach dem anderen (wie sie „entdeckt“ werden), um bestehende (oder neu) Planeten. Wenn der Planet nicht bereits in der Menge ist, wird er mit seiner aktuellen Menge bekannter Monde hinzugefügt. Wenn der Planet bereits in der Menge ist, möchte ich ihn entfernen, die neu entdeckten Monde zu seinen bekannten Monden hinzufügen und dann den Planeten wieder zu der Menge hinzufügen.

+0

Es scheint mir, dass eine 'Map' nützlicher wäre als ein' Set' für das, was Sie tun möchten. Sie können eine 'neue HashMap ' haben, wobei der Map-Eintrag der Name des String-Planeten -> Planet-Objekts ist. Dann können Sie 'solarSystem.get (" Jupiter "). AddMoon (" Titan ")' erstellen, ohne ein Zwischenobjekt zu erstellen. –

Antwort

2

Sie mit diesem unter Verwendung eines Map anstelle eines Set umgehen konnte - hinzufügen Planeten auf die Karte, wenn sie nicht bereits vorhanden sind; Füge Monde mit dem Planetennamen hinzu. Die Monde selbst bleiben ein Set, so dass Versuche, einen Mond hinzuzufügen, es nicht wiederholen.

ich etwas in dieser Richtung denke ...

public class Planet { 
    private final String name; 
    private final Set<String> moons = new HashSet<String>(); 

    // notice I set the name in the Constructor instead of a setter 
    public Planet(String name) { 
     this.name = name; 
    } 

    public void addMoon(String name) { 
     moons.add(name); 
    } 

    @Override 
    public boolean equals(Object obj) { ...same as yours... } 

    @Override 
    public int hashCode() { ...same as yours... } 

    public String getName() { return name; } 

    public Set<String> getMoons() { return moons; } 
} 


// ... elsewhere ... 

final Map<String,Planet> solarSystem = new HashMap<>(); 

public void addMoons(final String planet, final String... moons) 
{ 
    Planet p = solarSystem.get(planet); 
    if (p == null) { 
     p = new Planet(planet); 
     // add the Planet mapped by its name 
     solarSystem.put(p.getName(), p); 
    } 
    for (final String moon : moons) { 
     p.addMoon(moon); 
    } 
} 

Man könnte noch weiter gehen und machen das Solarsystem ein Objekt selbst, anstatt eine Karte oder ein Set.

+0

Vielen Dank für Ihre Antwort. Ich hatte versucht, den 'Map'-Ansatz vorwegzunehmen, aber eine Sorge, die für mich aufkam, ist, dass ich jetzt im Wesentlichen zwei Kopien des Namens habe, wobei einer der Map-Schlüssel ist und der andere das 'Name'-Feld des Objekts ist und dass du musst achte darauf, dass diese immer gleich sind, zB um sicherzustellen, dass "solarSystem.get (p.getName()). getName() == p.getName() 'immer. Ich nehme an, ich könnte das 'name'-Feld abschaffen und mich nur auf den Map-Schlüssel für diese Information verlassen ... – skrilmps

+0

@skrilmps Das ist der Grund, warum mein Beispielcode' solarSystem.put (p.getName(), p); '- - Es verwendet immer den tatsächlichen Namen. (BTW, '.getName() == p.getName()' ist wahrscheinlich nicht wahr, Sie müssen '.equals (p.getName())') verwenden - Sie benötigen eine Möglichkeit, um das Objekt von entweder der Set oder die Map, also müssen Sie in jedem Fall den Planetennamen außerhalb der Sammlung verwenden. Das Hauptproblem mit dem Set besteht darin, dass Sie das _actual object_ als "Schlüssel" benötigen, um das Objekt aus dem Set abzurufen, und wenn Sie es nicht aus dem Set abrufen müssen, haben Sie es bereits. –

0

Das Objekt, das Sie aus dem Set zurückholen möchten, ist das Objekt, das Sie bereits haben, vorausgesetzt, Sie haben es nicht geändert, seit es hinzugefügt wurde. Die Methode contains von Set verwendet die Methode equals des Objekts, um festzustellen, ob sie vorhanden ist.

Siehe API doco für contains: https://docs.oracle.com/javase/7/docs/api/java/util/Set.html#contains(java.lang.Object)

+0

Ich glaube nicht, dass das unbedingt stimmt. Wie Sie in meinem Code für die 'equals' Methode sehen, wird es eine Übereinstimmung geben, wenn die' name' Felder von zwei Objekten der Klasse 'Planet' übereinstimmen. Der Rest der Felder könnte jedoch anders sein. Sie sind also nicht dasselbe Objekt. Und in der Tat ist mein Ziel hier, die zwei Objekte, die den gleichen Namen haben, zu nehmen und sie anzupassen, bis alles andere übereinstimmt. – skrilmps

0

Sie brauchen nicht und es zu entfernen, um Planeten-Set zurückstellen. Sie können es einfach tun, wie diese

if(solarSystem.contains(addThisPlanet)) { 
    for(Planet currentPlanet : solarSystem){ 
    if(currentPlanet.equals(addThisPlanet)) 
{ 
for(String moon: addThisPlanet.getMoons()) 
{ currentPlanet .addMoon(moon); } 

    break; 
    } 
    }else { solarSystem.add(addThisPlanet); } 
+0

Danke. Ich glaube, dass diese Lösung funktionieren würde, aber Sie durchlaufen im Wesentlichen alle Elemente in der Menge, bis Sie die passende finden, die O (N) Zeit braucht. Dieselbe Suche wird für uns von 'HashSet's eingebauten Funktionen' remove' und 'contains' in O (1) Zeit erledigt. In meinem Kopf vereitelt es so den Zweck, ein 'Set' zu verwenden; Abgesehen von der ebenfalls erwünschten Einzigartigkeit der Mitglieder, könnte ich auch eine 'Liste' verwenden. Dies ist jedoch ein praktikabler Workaround für etwas, das wie ein großer Nachteil der Klasse "Set" erscheint, da es Ihnen keinen Zeiger auf das entfernte Objekt zurückgibt. – skrilmps

+0

Wenn es für Sie funktioniert, dann sollten Sie die Antwort annehmen und abstimmen, es hilft auch anderen – Alok