TreeMap.remove(value) - und nicht mit key! Geht das?

huckleberry

Bekanntes Mitglied
Hallo Forum,

wie Ihr hier http://www.java-forum.org/java-basi...4715-treemap-rueckgabe-compiler-warnings.html
sehen könnt, habe ich eine

Java:
TreeMap<Double, SpecialObj> myTreeMap = new TreeMap<Double, SpecialObj>();

Put() usw klappt super. Nur mit dem removen() harperts, denn mein Problem ist, dass die Methode remove(Object key) nur vom Typ key akzeptiert - also bei mir double.
Java:
myTreeMap.remove(myTreeMap.firstKey());
und myTreeMap liefert nur so keys wie firstKey() lastKey(). Ich kann nicht auf ein bestimmtes key zugreifen und somit löschen; wobei dieses bestimmte key vom value SpecialObj (jedes SpecialObj ist einmalig im TreeMap) abhängt.
Am liebsten hätte ich sowas wie

Java:
SpecialObj mySO = new SpecialObj(/*IrgendwasSinnvollesNatürlich*/);
myTreeMap.remove(mySO);

Habe aber lange rumprobiert, vergebens 🙁 Kann ich aus myTreeMap einen Eintrag löschen, undzwar nur mit dem value und nicht key?
 
durchlaufe das EntrySet, vergleiche den Value, erhalte so den Key und lösche den Key,
ne Map mappt nunmal von Key auf Value, nicht von Value auf Key

mit etwa Glück hängt der Key so stark mit dem Value zusammen, dass er sich aus dem Value direkt bestimmen läßt?
z.B. bei einer Map String Name -> Person sollte in der Person der Name als Attribut enthalten sein
 
Rufe ich es richtig auf?
Java:
myLocalVIR.remove(this.getKey(vpData, myLocalVIR));
, eigentlich ohne "this."
Java:
myLocalVIR.remove(getKey(vpData, myLocalVIR));

Die Methode ist in der gleichen Klasse implementiert..
Java:
/**
 * @param myVPD
 * @param myVIR
 * @return the keyPosition to remove in TreeMap or -1 if error
 */
public double getKey(SpecialObject mySO, TreeMap<Double, SpecialObject> myVIR) {
	Iterator it = mySO.entrySet().iterator();
	while (it.hasNext()) {
		Map.Entry entry = (Map.Entry)it.next();
		if (entry.getValue()==mySO) return (Double)entry.getKey();
	}
	return -1.0D;
}
 
Java:
public double getKey(SpecialObject mySO, TreeMap<Double, SpecialObject> myVIR) {
    for(Map.Entry<Double, SpecialObject> entry : myVIR.entrySet()) {
        if (entry.getValue().equals(mySO)) return entry.getKey(); //wenn equals ordentlich implementiert ist
    }
    return -1.0D;
}

Wenn du auf deine Daten mal Double -> MSO und mal MSO -> Double zugreifen müsstest, gibt es bei Google Code oder Apache Commons Collections auch "bidirektionale Maps", die genau das erlauben.
 
Was spricht dagegen über die [c]values()[/c]-Collection [c]remove(Object)[/c] zu rufen?

Java:
final Map<String, String> map = new TreeMap<String, String>();
map.put("A", "Huhu");
map.put("B", "Hallo");
map.put("C", "Ahoi");
map.values().remove("Hallo");
System.out.println(map);
Ausgabe:
Code:
{A=Huhu, C=Ahoi}

Ebenius
 
Von mir aus. Das erklärt aber trotzdem nicht, warum das da nicht Deinen Anforderungen genügt:
Code:
myLocalVIR.[B]values()[/B].remove(vpData);
Edit: Manchmal stehe ich auch auf dem Schlauch, vielleicht hab ich was nicht richtig begriffen.

Ebenius
 
Die Keys sind die Entfernungen zum Mittelpunkt.
Ich berechne dann hier die kürzesten Entfernungen zueinander (unter den Values), anhand der Values, wobei ich dann im Folgenden Einträge anhand dieser Values löschen möchte.
In dieser Berechnung spielen die Keys kaum eine Rolle.

Ich würde mal sagen, dass TreeMap für diesen Fall die völlig falsche Collection ist. Wenn du deine Problemstellung kurz mal erläuterst wird sich sicherlich eine elegantere Lösung finden lassen 🙂.
 
Wenn du deine Problemstellung kurz mal erläuterst wird sich sicherlich eine elegantere Lösung finden lassen 🙂.

Aus Sicht eines Knoten
Ich habe diese SpecialObj welche 'Knoten' repräsentieren. In diesen Objekten sind weitere Informationen, wie zB dessen Position.
Nun sind in dem Koordinatensystem irgendwo kleine Kreise, mit Mittelpunkt(Position) und Radius.

#1 - Knoten in Kreisen gruppieren:
Ich bin ein Knoten und möchte wenn ich mich in einem Kreis befinde, alle ANDEREN Knoten von diesem Typ SpecialObj, welche AUCH in so einem Kreis drin sind, sammeln - und wie schon geschehen, in einer TreeMap nach Abstand zum Mittelpunkt sortieren, undzwar dieser:
Java:
TreeMap<Double, SpecialObj> myTreeMap = new TreeMap<Double, SpecialObj>();
Nun rechne ich damit (Abstand zur Kreismitte) fröhlich umher - tut jetzt mal nichts zur Sache was genau.

#2 - Perlenkette bilden:
Durch #1 kenne ich nun alle anderen Knoten, die mit mir in einem Kreis sind.
Jetzt kommt eine Nadel mit Schnur aus der Kreismitte und spiesst den Knoten auf, welcher am nächsten zur Kreismitte ist.
Nun sucht er den nächsten und spiesst den auch auf.
Nun sucht er den nächsten und spiesst den auch auf.
....
Bis alle Knoten wie an einer Perlenkette (ArrayList) aufgehängt sind.


-->Und das habe ich algorithmisch so gelöst, dass von der ersten TreeMap ein entsprechender Knoten in eine neue Coollection (Arraylist) wander, folgendermaßen:
Ich suche Knoten mit kleinsten Abstand zur Kreismitte aus der ersten TreeMap und füge diese der ArrayList hinzu.
Dann gucke ich mir den letzten Knoten Aus der ArrayList an und suche mir dessen nächsten Nachbarn aus der nun verbleibenden TreeMap herraus, lösche den dort und füge ihn der ArrayList hinzu.
Dann gucke ich mir den letzten Knoten Aus der ArrayList an und suche mir dessen nächsten Nachbarn aus der nun verbleibenden TreeMap herraus, lösche den dort und füge ihn der ArrayList hinzu.
..
Bis meine TreeMap leer ist und alle meine Knoten als Perlenkette in der ArrayList abgelegt sind.

Java:
SpecialObj aNode; 
//schaffeschaffehäuslebaue und dann
myTreeMap.values().remove(aNode);
entspricht ja dann meinem "..., lösche den (Knoten) dort und..."

Wenn du meinst, das geht auch effektiver? Ich bin ganz Ohr! 😀
 
Zuletzt bearbeitet:
Die TreeMap ist bereits implementiert.
Eine Änderung würde folgerichtig Arbeit nach sich ziehen, welche ich auch gerne auf mich nehme, wenn dein Vorschlag Performance-Vorteile (oder andere?) mit sich bringt?????

Meinst du das lohnt sich? Die TreeMap wird von ein paar bis maximal so 500 Einträge haben..
Danke!
 
Wie Landei schon sagte, eine Liste sollte völlig ausreichen und wahrscheinlich einen wesentlich einfacheren Code produzieren.

Vom Algo. her sollte es sowas sein:
1) Füge alle Knoten der gesamten Karte in eine Liste ein.
2) Sortiere die Liste nach dem Abstand zum Ausgangsknoten.
3) Durchlaufe die Liste vom Ausgangsknoten (in der Liste der 1.Knoten) solange Abstand <= Radius.

Wenn ich jetzt nichts vergessen habe sollten das nur ein paar Zeilen Code sein.

Gruß

//Edit
Wenn ich Zeit habe schreibe ich Dir mal ein kleines Beispiel.

So hab mal was zusammengehackt:

Java:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;

public class Main {

    public static void main(String[] args) {
        //Beispielknoten erzeugen
        Random rand = new Random(456);
        List<Knoten> knotenliste = new ArrayList<Knoten>();
        for (int i = 0; i < 500; i++) {
            knotenliste.add(new Knoten(rand.nextInt(1000)));
        }

        //Startknoten - 4 ist willkürlich gewählt
        Knoten startknoten = knotenliste.get(4);

        //Sortiere die Liste nach dem Abstand zum Startknoten
        sortiere(knotenliste, startknoten);

        //Umfang festlegen - 322 ist willkürlich gewählt
        int umfang = 322;
        for (Knoten knoten : knotenliste) {
            if (Math.abs(startknoten.getPosition() - knoten.getPosition()) > umfang) {
                break;
            }
            System.out.println(/*Knoten ausgeben*/);
        }
    }

    //Sortierfuntkion
    private static List<Knoten> sortiere(List<Knoten> knotenliste, Knoten startknoten) {
        Collections.sort(knotenliste, getKnotenComparator(startknoten.getPosition()));
        return knotenliste;
    }

    //Comparator
    private static Comparator<Knoten> getKnotenComparator(final int startposition) {
        Comparator<Knoten> c = new Comparator<Knoten>() {

            public int compare(Knoten o1, Knoten o2) {
                int p1 = o1.getPosition() < startposition ? startposition * 2 - o1.getPosition() : o1.getPosition();
                int p2 = o2.getPosition() < startposition ? startposition * 2 - o2.getPosition() : o2.getPosition();
                return p1 - p2;
            }
        };
        return c;
    }
}

Java:
public class Knoten {

    private int position;
    //Hier noch weitere Attribute

    public Knoten(int position) {
        this.position = position;
    }

    public int getPosition() {
        return position;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Knoten other = (Knoten) obj;
        if (this.position != other.position) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        return this.position;
    }
}
 
Zuletzt bearbeitet:
Vielen Dank für deine Mühe. Ich habe es überflogen, jedoch auf Anhieb nicht verstanden.
Ich werde es mir am Wochenende genauer anschauen.

Remove scheint zu funzen, jedoch add geht nicht?!
Java:
tmpNode.setFromNode(nextToMittelpunkt); //Pseudo, für den Sinn
while( myLocalVIR.size() > 1){
	// Berechne NachKnoten als nächsten verbliebenen KnotenPool
	tmpNode.setToNode(calcNextNode(tmpNode.getFromNode(), myLocalVIR));
	tmpNode.calcDistanceBetween(); // Kantengewicht VonKnoten --> NachKnoten
	myLocalVIR.values().remove(tmpNode.getFromNode()); // entferne VonKnoten aus dem Pool
	// Kompletten Datensatz der ArrayList adden (macht er aber net :( )
	myReturnVIR.add(tmpNode);
	//Ausgabe Korrekt
	log.info("add to myReturnVIR: " +myReturnVIR.get(0).getFromNode().getId() +"\t"+myReturnVIR.get(0).getDistanceBetween() +"\t"+myReturnVIR.get(0).getToNode().getId());
        // Setzte NachKnoten dieser Runde als VonKnoten für die nächste Runde
	tmpNode.setFromNode(tmpNode.getToNode());
}

Code:
// log output aus Zeile 10 oeben im JavaCode, sieht gut aus!
//Jeweils nach add()
add to myReturnVIR: ID0	90.51541331525502	ID1
add to myReturnVIR: ID1	77.41086652758517	ID2
add to myReturnVIR: ID2	81.9865391882521	ID3

// Am Ende die ArrayList ausgeben (unten Javacode), hmm 3mal das gleiche ?!?!
// Aber falsch, sollte sowas wie oben rauskommen
ID3 81.9865391882521 ID3
ID3 81.9865391882521 ID3
ID3 81.9865391882521 ID3

Java:
for (int i = 0; i<myReturnVIR.size();i++) {
	log.info(	myReturnVIR.get(i).fromNode.getId()+" "
			+myReturnVIR.get(i).getDistanceBetween+" "
			+myReturnVIR.get(i).getToNode().getId());
}

Ich dachte immer, add() fügt an das Listenende hinzu?
Jedoch lese ich im Javacode in Zeile 10 immer bei index ..get(0).. den aktuellsten, zuletzt_hinzugefügten Wert. Also ein FIFO.

Dankbar für jegliche Hinweise.. mfg Huck
 
Zuletzt bearbeitet:
Jetzt habe ich die for-Schleife unten im Javacode mit der logAusgabe Zeile 10 oben im Javacode ersetzt..
Raus kommt folgendes:
ID1 90.51541331525502 ID1 1
ID2 77.41086652758517 ID2 1
ID2 77.41086652758517 ID2 2
ID3 81.9865391882521 ID3 1
ID3 81.9865391882521 ID3 2
ID3 81.9865391882521 ID3 3

Nach dem ersten add einmal ID1 90.51541331525502 ID1 1
Nach dem zweiten add zweimal ID2 77.41086652758517 ID2 #
Nach dem dritten add dreimal ID3 81.9865391882521 ID3 #

Die Distanzen scheinen richtig berechnet, nur die KnotenIDs sind fehlerhaft.
*grübel*
 

Zurück
Oben