# HashMap mit Object als Key



## turmaline (23. Apr 2010)

Hallo Leute,

ich habe folgende Frage: wie kann ich schnell auf das Key-Object meiner HashMap rankommen?

meine Map:


```
Map<Feature, Double> fmap = new HashMap <Feature, Double>();
```

nun möchte ich Feature schnell finden und an dem Objekt selbst etwas verändern:

zB:

```
feature.getFeatureDescriptor.setName("aa")
```

ich weiß keine andere Alternative als:


```
Iterator<Entry<Feature, Double>> i = fmap.entrySet().iterator();
		while(i.hasNext())
		{
			Entry<Feature, Double> entry = i.next();
			Feature feature = entry.getKey();
		}
```

dann muss ich aber die ganzen Entrys durchlaufen um auf die richtige Feature ranzukommen...??

kenn jemand eine alternative Möglichkeit?

Danke.

maldena


----------



## SlaterB (23. Apr 2010)

HashMap hat noch andere Methoden neben entrySet(),
alle mal anschauen?

was in jedem Fall nicht geht ist von einem Value direkt auf den Key zu schließen

edit: 
und immer die verkürzte for-Schleife bedenken

Iterator<Entry<Feature, Double>> i = fmap.entrySet().iterator();
        while(i.hasNext())
        {
            Entry<Feature, Double> entry = i.next();

==

for (Entry<Feature, Double> entry : fmap.entrySet()) {

}


----------



## Wortraum (23. Apr 2010)

1) Du hast als Schlüssel Feature, nicht Object. (Das soll so zwar sein, aber es läßt mich die Überschrift nicht mehr verstehen.)
2) Der Schlüssel dient eigentlich zum Finden des Wertes. Wenn Du es nun andersherum möchtest und einen bestimmten Schlüssel suchst, mußt Du die Schlüssel durchgehen. Bei einigen wenigen Schlüsseln ist das aber kein Problem; andernfalls benötigst Du eine andere oder eine zusätzliche Datenstruktur.


----------



## Noctarius (23. Apr 2010)

Einfach in Feature eine passende hashCode Methode implementieren


----------



## turmaline (23. Apr 2010)

allen vielen Dank für die Antwort

@SlaterB: ja ich habe die Methoden in HashMap angeschaut, hab ich keine passende gefunden..

@Wortraum: Feauture ist auch ein Object. Nein, ich möchte nicht "andersherum", d.h. der Wert interessiert mich erst einmal gar nicht. Ich muss an die Features run kommen können und an denen etwas ändern können.

@Noctarius: hashCode hab ich bei Feature schon überschrieben, das bringt mir nicht viel, ich kann nur fmap.containsKey(f) zu true auswerten... wenn das aber true liefert will ich NICHT an f rankommen, sondern an feature, welche in fmap gespeichert ist und dieselben werte wie f hat (in hashCode und equals ist es beschrieben wie ich die Features vergleiche)

Also ich muss doch alle features in fmap durchgehen um an einem Schlüßel etwas ändern zu können?

lG,madlena


----------



## SlaterB (23. Apr 2010)

> ja ich habe die Methoden in HashMap angeschaut, hab ich keine passende gefunden..

benenne doch mal alle, z.B. zuerst mal die die Listen oder Sets zurückgegeben wie entrySet() ja auch,
und warum du bei jeder glaubst, dass sie dir nicht hilft


----------



## turmaline (23. Apr 2010)

@SlaterB: heißt das, dass Du eine konkrete Methode kennst, die mir helfen könnte? 

ich bräuchte zB so was: fmap.keySet.get(feature);  ))))


----------



## turmaline (23. Apr 2010)

fmap.keySet.get(feature) das ist natürlich quatsch, weil ich eben feature selbst brauche und nicht den wert


----------



## SlaterB (23. Apr 2010)

keySet() war die Methode, auf die ich hinauswollte, ja,
die ist kürzer als der weg über entrySet() wenn du wie in deinem ersten Post angedeutet eine Schleife über alle Keys laufen lassen willst

was du stattdessen sonst noch möchtest wäre noch zu erraten, 
ich schrieb schon 
> was in jedem Fall nicht geht ist von einem Value direkt auf den Key zu schließen


fmap.keySet.get(feature);
klingt noch etwas merkwürdiger, wenn du schon ein feature-Objekt hast, was suchst du dann in der Map?
ist dort nicht dasselbe Objekt sondern ein anderes mit gleichen Inhalt?

ich kenne keine Methode die genau einen Key findet, auch nicht wenn du ein gleiches Objekt oder den hashCode vorliegen hast, nein,

du könntest aber vielleicht mit remove den alten Eintrag entfernen, evtl. den alten Value retten,
und das vorhandene neue Objekt neu einfügen


----------



## Lowpass (23. Apr 2010)

Wie schon geschrieben wurde: Du kannst bei einem HashMap nicht vom Value auf den Key schliessen. Nur scheint mir, dass Du den Key seltsam gewählt hast, wenn Dich der Key mehr interessiert als der Value.

Ich hatte kürzlich den Fall, dass ich zum einen eine HashMap verwenden wollte, aber gleichermassen an Key und Value interessiert war. Ich habe eine eigene Klasse erstellt, welche zwei HashMaps verwaltet und dafür sorgt, dass immer beide den gleichen Stand haben.

So kann ich je nach Abfrage auf die eine oder andere HashMap zugreifen. Das lässt sich sehr einfach umsetzen.


----------



## turmaline (23. Apr 2010)

was ich möchte sieht so aus:


```
if(doc.getDocumentFeatureMap().containsKey(f))
						{
							f.getFeatureDescriptor().setFreq(f.getFeatureDescriptor().getFreq()+1);
						}
						else 
						{
							f.getFeatureDescriptor().setFreq(1);
						}
						doc.getDocumentFeatureMap().put(f, 1.0);
```

zu der map werden immer mal wieder neue Features hinzukommen. Wenn aber inhaltlich gleiche Feature bereits in map vorhanden ist, sollte der Zäler erhöht werden... oh je... vielleicht ist das einfach eine kranke idee... der wert aber wird erst später ermittelt..


----------



## SlaterB (23. Apr 2010)

dein Code zeigt in keiner Weise, warum du nun in der Map nach einem Key suchst, 
containsKey funktioniert doch?


----------



## Lowpass (23. Apr 2010)

Brauchst Du denn den Value überhaupt irgendwann mal?
Falls nicht, solltest Du eh HashSet nehmen und nicht HashMap.


----------



## xerberuz (23. Apr 2010)

Es ist nicht sehr ratsam den Schlüssel einer HashMap mutable zu machen. Ich meine das kann ganz schnell nach hinten losgehen, sollte sich der hashcode dadurch ändern. 

Würde in deinem Fall nicht eine Liste  ausreichen?


----------



## turmaline (23. Apr 2010)

@alle: ja ich brauche nachher den Value, später...

@xerberuz: hashCode hab ich überschrieben und er ändert sich nicht, wenn sich andere Parameter von Feature bzw von FeatureDescriptor ändern

@SlaterB: containsKey funktioniert aber der Key selbst muss geändert werden.. so wie es in meinem Code steht wird nicht funktionieren, weil der Key ist nicht dasselbe wie f... nur das Gleiche... (kann man das verstehen....????)


----------



## Landei (23. Apr 2010)

Wenn man in beide Richtungen abfragen will, nimmt man am besten eine bidirektionale Map, z.B. die von Google Collections oder Apache Common Collections.


----------



## bygones (23. Apr 2010)

```
private Feature findFeature(Map<Feature, X>features, Feature toFind) {
    for (Feature each : features.keySet()) {
      if (each.equals(toFind)) {
          return each;
      }
    }
    return null;
}
```

sein problem ist ja, dass er *2* Feature Objekte hat, die aber gleiche sind. D.h. per equals bzw hashcode gleich evaluieren, weswegen zb die containsKey richtig beantwortet. Das aendern des einen Objekts zieht aber keine Aenderung des in der map vorhandenen mit sich.

Ergo das gleiche, aber nicht das selbe.

wenn ichs richtig verstanden hab ;-)


----------



## SlaterB (23. Apr 2010)

> so wie es in meinem Code steht wird nicht funktionieren, weil der Key ist nicht dasselbe wie f... nur das Gleiche... (kann man das verstehen....????)

nun ja, verstehen kann man es schon, hatte ja schon einiges dazu geschrieben, hast du nur bisher nie deutlich ausgesprochen,
bidirektionale Map könnten dabei ein wenig helfen, aber dann müsste man den value zum kopierten Key laden und mit dem Value dann den Originalkey holen,
aufwendig,

andere Möglichkeiten:
- eine zweite Map Key -> Key, mit dem Copy-Key bekommt man dort den Original-Key,

- Map umbauen, nicht Key -> Value, sondern Key -> neues Objekt, welches Key + Value enthält, 
oder im Value den Key direkt verlinken als ein Attribut, falls die Value-Klasse änderbar ist,
ach ne das soll ja nur ne Zahl sein

- oder nur die Map Key -> Key und im Key den Value, also die Zahl speichern,
deinem Code nach willst du doch im Key sowieso hochzählen, was bedeutet der immergleiche Value 1.0 in der Map?


----------



## bygones (23. Apr 2010)

wenns wirklich nur um die Frequenzen geht kannst du dir auch mal Bag implementierunge anschauen

Bag (Commons Collections 3.2.1 API)


----------



## turmaline (23. Apr 2010)

vielen Dank an alle, die mir geantwortet haben!!!

@bygones: ich wollte eben nicht den ganzen Set durchgehen...

ich hab micht jetzt doch für eine Liste entschieden und Value in die Parameter des FeatureDescriptors mitaufgenommen.

so sieht es jetzt aus:


```
if(doc.getDocumentFeatures().contains(f))
						{
							int index = doc.getDocumentFeatures().indexOf(f);
							doc.getDocumentFeatures().get(index).getFeatureDescriptor().incrementFreq();
						}
						else
						{
							f.getFeatureDescriptor().incrementFreq();
							doc.getDocumentFeatures().add(f);
						}
```

wenn jemand Fehler sieht oder mögliche Probleme, bitte melden 

lG,Madlena


----------



## Wortraum (23. Apr 2010)

turmaline hat gesagt.:


> Feauture ist auch ein Object


Feature ist Feature, Object ist Object, Feature ist nicht Object, Feature erbt von Object. 

> Nein, ich möchte nicht "andersherum", d.h. der Wert interessiert mich erst einmal gar nicht.
Du willst nach einem bestimmten Merkmal suchen (der Schlüssel) und dazu den entsprechenden Wert (ein Feature‐Objekt) bekommen. Du verwendest die Feature‐Objekte aber als Schlüssel, und die mußt Du deshalb der Reihe nach durchsuchen, um das mit dem richtigen Merkmal zu finden. Wenn das nicht verkehrt herum ist, dann weiß ich es auch nicht. 

> ich hab micht jetzt doch für eine Liste entschieden
Die mußt Du doch genauso durchgehen, um ein Feature‐Objekt zu finden. Die for-Schleife ist zwar nun einmal in contains() und einmal in indexOf() versteckt – jedenfalls bei ArrayList und LinkedList –, aber mehr als den psychologischen Effekt „aus dem Auge, aus dem Sinn“ hat das auch nicht.

Wenigstens das contains() solltest Du rausnehmen,

```
List<Feature> features = doc.getDocumentFeatures();
int index = features.indexOf(f);
if (index >= 0) {
    features.get(index).getFeatureDescriptor().incrementFreq();
} else {
    f.getFeatureDescriptor().incrementFreq();
    features.add(f);
}
```


----------



## turmaline (24. Apr 2010)

Wortraum hat gesagt.:


> Feature ist Feature, Object ist Object, Feature ist nicht Object, Feature erbt von Object.



oh... und ich dachte die ganze Zeit dass eine Katze auch ein Tier ist??? aber sie erbt ja nur von Tier... :shock:



Wortraum hat gesagt.:


> Die mußt Du doch genauso durchgehen, um ein Feature‐Objekt zu finden. Die for-Schleife ist zwar nun einmal in contains() und einmal in indexOf() versteckt – jedenfalls bei ArrayList und LinkedList –, aber mehr als den psychologischen Effekt „aus dem Auge, aus dem Sinn“ hat das auch nicht.



ok danke dass Du mich darauf hingewiesen hast. das hab ich jetzt ehrlich gesagt nicht gewusst.. Vielleicht sollte ich eine Map<Feature, FeatureDescriptor> anlegen...??



Wortraum hat gesagt.:


> Wenigstens das contains() solltest Du rausnehmen,


danke, das mach ich.


----------



## turmaline (24. Apr 2010)

mit der Liste denke ich ist das keine gute Idee... ((( wenn die Liste richtig lange ist, ist das echt keine gute idee(((


----------



## Wortraum (24. Apr 2010)

turmaline hat gesagt.:


> oh... und ich dachte die ganze Zeit dass eine Katze auch ein Tier ist??? aber sie erbt ja nur von Tier... :shock:


Trotzdem ist List<Katze> etwas anderes als List<Tier>. Sie können nicht die gleichen Objekte enthalten, und sie geben unterschiedliche Typen zurück. Vielleicht ist das aber nur eine Frage der Formulierung.



> mit der Liste denke ich ist das keine gute Idee... ((( wenn die Liste richtig lange ist, ist das echt keine gute idee(((


Es kommt darauf an, wieviele Elemente in der Liste sind und wie oft Du sie durchsuchst. Ein paar Tausend Elemente sind allgemein nicht viel.


----------



## Lowpass (24. Apr 2010)

Wortraum hat gesagt.:


> Trotzdem ist List<Katze> etwas anderes als List<Tier>. Sie können nicht die gleichen Objekte enthalten, und sie geben unterschiedliche Typen zurück.



Da stehe ich ja definitiv auf der Seite von turmaline. Feature _ist_ ein Object und Katze _ist_ ein Tier und alles was List<Katze> enthält, kannst Du auch in List<Tier> reinpacken, weil alle Katzen eben Tiere sind.
Umgekehrt geht das natürlich nicht - aber es hat ja auch niemand behauptet, dass Object ein Feature ist.


----------



## turmaline (24. Apr 2010)

Leute, allen vielen Dank für die Diskussion!

Also ich bleibe erst einmal bei der Liste. Die Lösung sieht nun so aus wie Wortraum (oben) empfohlen hat (ohne contains) und sie funktioniert. Vielleicht ist das konteptionell nicht so gut, was ich mir da überlegt habe aber jetzt fällt mir nichts besseres ein. Ich dachte, HashMap wäre besser... 

Könnte ein Key ein Paar von Strings darstellen?

z.B. <x, a> und <x, t> wären verschiedene Keys... dann könnte mein Value eine Feature sein.. oder ist es total krank??

lG,madlena


----------



## Wortraum (24. Apr 2010)

Lowpass hat gesagt.:


> Da stehe ich ja definitiv auf der Seite von turmaline


Verdammt! 

Ich bleibe jedenfalls dabei: Typparameter kann man nicht gleichbehandeln, und List<Katze> ist etwas anderes als List<Tier>. Aber die Diskussion können wir uns sparen, der TO kann ja gerne Object da reinschreiben und schauen, ob sein Programm noch funktioniert.  Und er kann dann auch gerne Katze und Feature und sonstwas reinstecken, was zwar geht, aber kompliziert und sinnfrei ist.

Du mußt ja bedenken, daß man Katzen nicht nur in die Liste steckt, sondern auch wieder herausnimmt, und für diese „andere Richtig“ spielt der Typparameter ebenfalls eine Rolle.

Natürlich ist eine Katze ein Tier und Feature ist Object, ich weiß sehr wohl, was Du meinst. Vielleicht verstehst Du aber auch, was ich meine, und dann wäre ja alles in Ordnung. 



turmaline hat gesagt.:


> Könnte ein Key ein Paar von Strings darstellen?


Du kannst jedes Objekt als Schlüssel verwenden, also auch wieder Listen, Felder oder sonstwas.


----------



## turmaline (24. Apr 2010)

@Wortraum: ich verstehe schon was Du meinst... das sind ja alles die Grundlagen der OO-Programmierung... ich werde bei Gelegenheit in einem Lehrbuch nachschlagen 

ja, das ist schon klar dass ich jedes Object als Key verwenden kann, die Frage war aber ob es etwas passendes gibt, wo man String, String speichern kann. Dabei ist nur die Kombination eindeutig, deswegen würde hier HashMap nicht mehr passen..


----------



## Lowpass (24. Apr 2010)

Wortraum hat gesagt.:


> Feature ist Feature, Object ist Object, Feature ist nicht Object, Feature erbt von Object.



Dieser Satz ist verwirrend formuliert und verleitet zu falschen Annahmen.
Feature ist nicht gleich Object, stimmt. Aber Feature IST ein Object. 
Auto ist auch nicht gleich Fahrzeug, aber Auto IST ein Fahrzeug.

Du willst vielleicht sagen, dass es keine identischen Mengen sind, aber es ist eben eine _Unter_menge und alles was zur Untermenge gehört, ist auch automatisch Element der Obermenge. Zudem können sich die in einem System befindlichen Elementen jederzeit in einem Zustand befinden, in denen Menge und Untermenge identische Mengen sind.



> Trotzdem ist List<Katze> etwas anderes als List<Tier>. Sie können nicht die gleichen Objekte enthalten,


Und das ist auch nicht ganz eindeutig formuliert, denn jede List<Katze> wirst Du _immer_ komplett in eine List<Tier> übernehmen können. Tatsächlich können sich theoretisch beide Mengen in einem absolut identischen Zustand befinden und Du wirst _immer_ jedes Objekt aus List<Katze> ohne Casting und ohne Verletzung der Type Safety in eine List<Tier> übernehmen können. 
"Sie können nicht die gleichen Objekte enthalten" ist also wirklich unglücklich ausgedrückt.


----------



## Wortraum (25. Apr 2010)

Lowpass hat gesagt.:


> Feature ist nicht gleich Object, stimmt. Aber Feature IST ein Object.


Ok, das unterschreibe ich.


----------



## turmaline (25. Apr 2010)

schön..!!  alle sind zufrieden.. meine letzte Frage blieb nur unbeantwortet, aber vielleicht hab ich sie uneindeutig gestellt und dabei kein Fragezeichen hinzugefügt..(sowas identifizieren die Männer nicht als Frage)..

die beste Lösung meines Problems wäre eine HashMap <Key, Feature>, wobei Key aus zwei Strings besteht. Der erste String sowie der Zweite können sich wiederholen, nur die Kombination ist eindeutig. Vieleicht soll ich eine Klasse FeatureKey erstellen, hashCode und equals überschreiben und auf diese Weise auf meine Features schnell zugreifen können? 

Wird diese Lösung schnell??????? So muss ich nicht die ganzen Features in HashMap durchgehen...

lG,madlena


----------



## Wortraum (25. Apr 2010)

So etwas ist natürlich schwer zu beurteilen, wenn man das Projekt und das Vorhaben nicht kennt. Es ist jedenfalls eine Möglichkeit, und die Suche mittels for-Schleife entfiele. Je „verschiedener“ die Werte von hashCode() sind, desto effizienter wird das ganze.


----------



## turmaline (25. Apr 2010)

ok, ich markiere mal das Thema als erledigt und danke allen noch einmal für die Diskussion!


----------

