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

turmaline

Bekanntes Mitglied
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?

Java:
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
 
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.
 
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?

Java:
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);
                }
            }
        }
    }
 
Was heißt "verändern"? Sind aufeinmal andere Daten vorhanden oder fehlen welche?
Ich kann jetzt so keinen logikfehler in dem Code finden.
 
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.

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

Die EInträge, die ich gelöscht habe fehlen...
 
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
 
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.
 
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.
Java:
attributes.remove(key);

ansonsten funktioniert die Methode equalsMaps nicht mehr, die Daten (attributes) werden aber nicht verändert
Java:
tmpAttributes.remove(key);
 
So in der Art müsste es dann funktionieren, denke ich:
Java:
    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;
    }
 
so funktioniert es jetzt hervorragend! danke an alle, insbesondere an Illuvatar

Java:
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;
    }
 
mit google collections gehts schöner:
Java:
 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:
Java:
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);
 
Zuletzt bearbeitet von einem Moderator:
mit google collections gehts schöner:
Java:
 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);
    }
ok mag sein dass es schöner ist.

oder auch standard api:
Java:
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);

das geht nicht. Constants.ATTACHMENT_CONTENT_NAME _kann_ nur die innere Map beinhalten.
 
ah ok... dann gehen beide nicht - sry - ist aber auch ne ziemlich krude struktur imo... naja bygones
 
ah ok... dann gehen beide nicht - sry - ist aber auch ne ziemlich krude struktur imo... naja bygones

kein problem.
krude? naja..
Java:
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.
 
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.
 
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.....
 

Zurück
Oben