# Gleichheit von zwei Maps Map <String, Map <String, String>>



## turmaline (16. Aug 2010)

Hallo Leute,

ich sitze hier an einem Stück-Code, den ich eigentlich nur zum Testen brauche und er funktioniert nicht richtig. Vielleicht habe ich es viel zu kompliziert gemacht?
Ich habe folgendes Problem:
zwei Maps sind zu vergleichen:
Map<String, Map <String, String>> _attachments (ist ein Member der Klasse OntologyMap) und Map <String, Map <String, String>> map (die als Parameter der methode equals übergeben wird).

Es gibt ein Aber: ein Eintrag in Map<String, String> mit einem bestimmten Key wird ignoriert.
Unten sieht ihr die Methode equals.. Sie funktioniert nicht richtig, das heißt sie liefert true sogar wenn einige Einträge in Map <String, String> nicht übereinstimmen. Sieht ihr den logischen Fehler? Geht es sowas einfacher?

Ist das überhaupt angebracht solche Methoden zum Testen zu verwenden?


```
public boolean equals (OntologyMap map) {
        boolean eq = false;
        if (_attachments.size() == map.getAttachments().size()) {
            for (Entry <String, Map <String, String>> attm : _attachments.entrySet()) {
                String id = attm.getKey();
                Map <String, String> attributes = attm.getValue();
                if (map.containsAttachment(id)) {
                    Map <String, String> otherAttributes = map.getAttachment(id);
                    if (attributes.size() == otherAttributes.size()) {
                        for (Entry <String, String> attr : attributes.entrySet()) {
                            String attrName = attr.getKey();
                            String attrValue = attr.getValue();
                            // content is not checked
                            if (!attrName.startsWith(Constants.ATTACHMENT_CONTENT_NAME) && 
                                    otherAttributes.containsKey(attrName)) {
                                String otherAttrValue = otherAttributes.get(attrName);
                                if (attrValue.equals(otherAttrValue)) {
                                    eq = true;
                                } // if the value of this attribute is equal the name of the other attribute
                                else {
                                    eq = false;
                                }
                            } // if other attributes contain an attribute with this name 
                            else {
                                eq = false;
                            }
                        } // for each attribute
                    } // if size of the attributes map equals size of other attributes map
                    else {
                        eq = false;
                    }
                } // if the map to compare contains an attachment with this id
                else {
                    eq = false;
                }
            } // for each entry in the map
        } // if size of this map and of the map with which to compare is equals
        return eq;
    } // equals
```

Bitte um Hilfe.

Gruß, madlena


----------



## XHelp (16. Aug 2010)

Warum nicht

```
map1.equals(map2)
```
?


----------



## turmaline (17. Aug 2010)

weil ein Eintrag der innderen Map mit einem bestimmten key ignoriert werden soll.


----------



## Sued_Faust (17. Aug 2010)

Ich würde die Map mit dem key, welches ignoriert werden soll, in eine Temp-Map schmeißen und dabei den zu ignorierende Wert rausschmeißen. Danach dann halt mittels equals vergleichen. Geht natürlich nur wenn der Wert der Ignoriert werden soll immer der selbe ist.


----------



## turmaline (17. Aug 2010)

ich hatte gerade dieselbe Idee, probiere gleich aus. Danke.


----------



## turmaline (17. Aug 2010)

ok so funktioniert es. aber somit verändere ich den inhalt von map1 und map2, obwohl ich sie in tmpAtt1 und tmpAtt2 speichere..(( wie könnte ich das ändern?


```
protected boolean equalsMaps (OntologyMap map1, OntologyMap map2) {
        Map <String, Map <String, String>> tmpAtt1 = new HashMap <String, Map <String, String>> ();
        Map <String, Map <String, String>> tmpAtt2 = new HashMap <String, Map <String, String>> ();
        tmpAtt1.putAll(map1.getAttachments());
        tmpAtt2.putAll(map2.getAttachments());
        
        ignoreContentAttribute(tmpAtt1);
        ignoreContentAttribute(tmpAtt2);
        
        if(tmpAtt1.equals(tmpAtt2))
                return true;
        else return false;
    }

    private void ignoreContentAttribute(Map<String,Map<String,String>> attachments) {
        for (Map<String,String> attributes : attachments.values()) {
            Map <String, String> tmpAttributes = new HashMap <String, String> ();
            tmpAttributes.putAll(attributes);
            for (String key : tmpAttributes.keySet()) {
                if (key.startsWith(Constants.ATTACHMENT_CONTENT_NAME)) {
                    attributes.remove(key);
                }
            }
        }
    }
```


----------



## Sued_Faust (17. Aug 2010)

Was heißt "verändern"? Sind aufeinmal andere Daten vorhanden oder fehlen welche?
Ich kann jetzt so keinen logikfehler in dem Code finden.


----------



## faetzminator (17. Aug 2010)

Zeile 21 berichtigen?


----------



## turmaline (17. Aug 2010)

Sued_Faust hat gesagt.:


> Was heißt "verändern"? Sind aufeinmal andere Daten vorhanden oder fehlen welche?
> Ich kann jetzt so keinen logikfehler in dem Code finden.



ja es fehlen welche nach der ausführung.


```
assertTrue (equalsMaps(sameMap, otherMap));
       
System.out.println(sameMap.getAttachments());
```

Die EInträge, die ich gelöscht habe fehlen...


----------



## XHelp (17. Aug 2010)

Sicher, dass du nicht woanders die Inhalte veränderst?
Du kannst übrigens es auch so schreiben:
[JAVA=10]
return tmpAtt1.equals(tmpAtt2);
[/code]

Und meiner Meinung nach kannst du die Collection nicht verändern, wärend du über diese iterierst


----------



## turmaline (17. Aug 2010)

@faetzminator: stimmt... aber dann funktioniert die equalsMaps-Methode nicht mehr((


----------



## XHelp (17. Aug 2010)

was stimmt?
[EDIT]ok, hat sich schon erledigt  [/EDIT]


----------



## turmaline (17. Aug 2010)

XHelp hat gesagt.:


> Sicher, dass du nicht woanders die Inhalte veränderst?
> Du kannst übrigens es auch so schreiben:
> [JAVA=10]
> return tmpAtt1.equals(tmpAtt2);
> [/code]



danke hab jetzt gemacht



XHelp hat gesagt.:


> Und meiner Meinung nach kannst du die Collection nicht verändern, wärend du über diese iterierst



ich verändere die Daten nirgendwo mehr..


----------



## Sued_Faust (17. Aug 2010)

Lass dir doch sonst mal die original Maps vor der ausführung deines neuen Codes Ausgeben.


----------



## XHelp (17. Aug 2010)

turmaline hat gesagt.:


> ich verändere die Daten nirgendwo mehr..


ja, hab mich ein wenig in den Namen der Variablen verguckt.


----------



## Illuvatar (17. Aug 2010)

Dein Problem ist, dass zum Beispiel map1 und tmpAtt1 die gleichen Maps enthalten. Wenn du die verschachtelten Maps kopierst, musst du auch für die enthaltenen Maps neue Maps anlegen, sonst löschst du eben in Zeile 21 tatsächlich auch aus den übergebenen Maps ein Objekt.


----------



## turmaline (17. Aug 2010)

Sued_Faust hat gesagt.:


> Lass dir doch sonst mal die original Maps vor der ausführung deines neuen Codes Ausgeben.



die Original-Maps enthalten die Einträge, die ich später lösche. Danach aber nicht mehr. Im Prinzip ist das in diesem konkreten Code egal, aber trotzdem unschön, dass die Daten verändert werden, während sie eigentlich nur vergliechen werden sollten.

wenn die Zeile "21" so bleibt, dann funktioniert die Methode equalsMaps, die Daten werden aber verändert.

```
attributes.remove(key);
```

ansonsten funktioniert die Methode equalsMaps nicht mehr, die Daten (attributes) werden aber nicht verändert

```
tmpAttributes.remove(key);
```


----------



## turmaline (17. Aug 2010)

Illuvatar hat gesagt.:


> Dein Problem ist, dass zum Beispiel map1 und tmpAtt1 die gleichen Maps enthalten. Wenn du die verschachtelten Maps kopierst, musst du auch für die enthaltenen Maps neue Maps anlegen, sonst löschst du eben in Zeile 21 tatsächlich auch aus den übergebenen Maps ein Objekt.



Du hast recht. Ich versuch jetz das


----------



## Sued_Faust (17. Aug 2010)

Illuvatar hat wohl recht.


----------



## Illuvatar (17. Aug 2010)

So in der Art müsste es dann funktionieren, denke ich:

```
protected boolean equalsMaps (OntologyMap map1, OntologyMap map2) {
        Map <String, Map <String, String>> tmpAtt1 = copyIgnoringContent(map1.getAttachments());
        Map <String, Map <String, String>> tmpAtt2 = copyIgnoringContent(map2.getAttachments());

        return tmpAtt1.equals(tmpAtt2);
    }
    
    private Map<String,Map<String,String>> copyIgnoringContent(Map<String,Map<String,String>> attachments) {
        Map<String,Map<String,String>> newMap = new HashMap<String,Map<String,String>>();
        for (String id : attachments.keySet()) {
            Map<String,String> attributes = attachments.get(id);
            Map<String,String> newAttributes = new HashMap<String,String>();
            for (String key : attributes.keySet()) {
                if (!key.startsWith(Constants.ATTACHMENT_CONTENT_NAME)) {
                    newAttributes.put(key, attributes.get(key));
                }
            }
            newMap.put(id, newAttributes);
        }
        return newMap;
    }
```


----------



## turmaline (17. Aug 2010)

so funktioniert es jetzt hervorragend! danke an alle, insbesondere an Illuvatar


```
protected boolean equalsMaps (OntologyMap map1, OntologyMap map2) {
               
        Map <String, Map <String, String>> tmpAtt1 = copyIgnoringContent(map1.getAttachments());
        Map <String, Map <String, String>> tmpAtt2 =copyIgnoringContent(map2.getAttachments());
        
        return tmpAtt1.equals(tmpAtt2);
    }

    private Map<String,Map<String,String>> copyIgnoringContent(Map<String,Map<String,String>> attachments) {
        Map<String,Map<String,String>> newMap = new HashMap<String,Map<String,String>>();
        for (String id : attachments.keySet()) {
            Map<String,String> attributes = attachments.get(id);
            Map<String,String> newAttributes = new HashMap<String,String>();
            for (String key : attributes.keySet()) {
                if (!key.startsWith(Constants.ATTACHMENT_CONTENT_NAME)) {
                    newAttributes.put(key, attributes.get(key));
                }
            }
            newMap.put(id, newAttributes);
        }
        return newMap;
    }
```


----------



## bygones (17. Aug 2010)

mit google collections gehts schöner:

```
private static final Predicate<String> filterFoo = new Predicate<String>() {
   @Override
   public boolean apply(String input) {
      return !input.equals(Constants.ATTACHMENT_CONTENT_NAME); // oder startswith oder was auch immer
   }
  };
  protected boolean equalsMaps (OntologyMap map1, OntologyMap map2) {
        Map<....> filteredMap1 = Maps.filter(map1.getAttachments(), filterFoo);
        Map<....> filteredMap2 = Maps.filter(map2.getAttachments(), filterFoo);
        return filterMap1.equals(filterMap2);
    }
```

oder auch standard api:

```
Map<String, Map<String, String>> filteredMap1= new HashMap<String, Map<String, String>>(map1.getAttachments());
filteredMap1.remove(Constants.ATTACHMENT_CONTENT_NAME);

Map<String, Map<String, String>> filteredMap2= new HashMap<String, Map<String, String>>(map2.getAttachments());
filteredMap2.remove(Constants.ATTACHMENT_CONTENT_NAME);

return filteredMap1.equals(filterMap2);
```


----------



## turmaline (17. Aug 2010)

bygones hat gesagt.:


> mit google collections gehts schöner:
> 
> ```
> private static final Predicate<String> filterFoo = new Predicate<String>() {
> ...


ok mag sein dass es schöner ist.



> oder auch standard api:
> 
> ```
> Map<String, Map<String, String>> filteredMap1= new HashMap<String, Map<String, String>>(map1.getAttachments());
> ...



das geht nicht. Constants.ATTACHMENT_CONTENT_NAME _kann_ nur die innere Map beinhalten.


----------



## bygones (17. Aug 2010)

ah ok... dann gehen beide nicht - sry - ist aber auch ne ziemlich krude struktur imo... naja bygones


----------



## turmaline (17. Aug 2010)

bygones hat gesagt.:


> ah ok... dann gehen beide nicht - sry - ist aber auch ne ziemlich krude struktur imo... naja bygones



kein problem.
krude? naja..

```
Map <String, Map <String, String> attachments;
```

Jeder Eintrag dieser Map beschreibt ein Attachment, wobei key die id ist und die innere Map die Attribute beschreibt, welche bei verschiedenen Attachments variieren, z.B. ein Attachment hat einen Namen und einen Content, das andere hat aber nur einen Namen und keinen Content..

mir ist nichts anderes eingefallen, wie ich das sonst lösen kann.


----------



## bygones (17. Aug 2010)

```
Map<String, Attachment> attachments
```
 ?


----------



## turmaline (17. Aug 2010)

ja.. und wo ist der Unterschied? meinst Du würde es mir das Leben erleichtern?


----------



## bygones (17. Aug 2010)

turmaline hat gesagt.:


> ja.. und wo ist der Unterschied? meinst Du würde es mir das Leben erleichtern?


ich werde hier nicht die Vorteile und Nutzen von Objektorientierter Programmierung beschreiben.... das arbeiten mit vollwertigen Objekten ist einfach, übersichtlicher, wartbarer und verständlicher etc etc etc


----------



## turmaline (17. Aug 2010)

bygones hat gesagt.:


> ich werde hier nicht die Vorteile und Nutzen von Objektorientierter Programmierung beschreiben.... das arbeiten mit vollwertigen Objekten ist einfach, übersichtlicher, wartbarer und verständlicher etc etc etc



naja mann muss aber auch nicht übertreiben. in diesem fall würde es nur den code unnötig vergrößern.
OntologyMap ist eine Struktur, die ich als Hilfe verwende, sie enthält attachments. Attachment würde dann einfach eine eigene Map beinhalten, die die Attribute speichert. Ich finde es an dieser Stelle einfach unnötig. Geschmacksache.


----------



## bygones (17. Aug 2010)

turmaline hat gesagt.:


> naja mann muss aber auch nicht übertreiben. in diesem fall würde es nur den code unnötig vergrößern.
> OntologyMap ist eine Struktur, die ich als Hilfe verwende, sie enthält attachments. Attachment würde dann einfach eine eigene Map beinhalten, die die Attribute speichert. Ich finde es an dieser Stelle einfach unnötig. Geschmacksache.


OOP ist nicht wie Homöopathie - sie funktioniert auch wenn man nicht daran glaubt.....


----------



## turmaline (17. Aug 2010)

bygones hat gesagt.:


> OOP ist nicht wie Homöopathie - sie funktioniert auch wenn man nicht daran glaubt.....



gut dass Du es sagst.. ich werde es im Auge behalten


----------

