how can i iterate through two HasMap at once, i want o compare the values of two hashmaps

106 views Asked by At

here is the half code im making for isomorphic strings,

    public boolean isIsomorphic(String s, String t) {
        String[] ss=s.split("");
        String[] tt=t.split("");
        HashMap<String, Integer> smap=new HashMap<>();
        HashMap<String, Integer> tmap=new HashMap<>();
        int tint,sint;
        for(int i=0;i<ss.length;i++){
            if(!smap.containsKey(ss[i])){
                smap.put(ss[i], 1);
            }else{
                sint=smap.get(ss[i]);
                smap.put(ss[i], sint++);
            }
        }
        
        
        for(int i=0;i<tt.length;i++){
            if(!tmap.containsKey(tt[i])){
                tmap.put(tt[i], 1);
            }else{
                tint=tmap.get(tt[i]);
                tmap.put(tt[i], tint++);
            }
        }
//below space to iterate and check if both hashmap values are sequentially 
    }

below is the solution i found ,i was about to use this logic but i cant compare two hashmaps, as both have different keys... here all keys from both hashmaps are different, and values sequence wise might be same, thats all i wanna check...if all values are sequentially same or equal.

for (Map.Entry<String, Object> entry : map.entrySet()) {
     String key = entry.getKey();
     Object value = entry.getValue();
     // ... 
}
2

There are 2 answers

2
Old Dog Programmer On

I am going to address the problem you asked: How might the contents of two HashMap Objects be compered. This might or might not solve the problem of verifying two String Objects are isomorphic.

Before addressing your question, I'd like to go off-topic:

I'd like to expand on a comment I made: Don't Repeat Yourself. In the code shown in your question, you have two sections that load a Map, one section for each String parameter. You could reduce this to a method, and call it twice. Here is code similar to yours, but as a method:

public static LinkedHashMap<Character, Integer> loadMap (String str) {
        LinkedHashMap <Character, Integer> map = new LinkedHashMap <> ();
        char ss;
        int count = 0;
        for(int i=0;i<str.length();i++){
            ss = Character.toLowerCase(str.charAt(i));
            if(!map.containsKey(ss)){
                map.put(ss, 1);
            }else{
                count=map.get(ss);
                map.put(ss, count++);
            }
        }     
        System.out.println (mapToString (map));
        return map;
    }
  • This code uses a HashMap<Character, Integer> instead of HashMap<String, Integer>.
  • This code converts uppercase characters to lowercase. However, this is probably not desirable, if I understand the instructions at LeetCode 205 properly.
  • I have no good reason for using Character instead of String as keys, nor for using the charAt (int index) method of String instead of an array. It's my preference.
  • By the way, the String API offers a toCharArray() method.
  • The code contains a bug. The bug is in the code in the original question, and I preserved it in creating this method. I encourage you to find and fix the bug.
  • Note that once you find the bug, in your original code, you will have to fix it twice. Using this method, and calling it twice, you will have to fix it once. This is one of the advantages of "Don't Repeat Yourself".
  • For debugging and testing, you might find the overloaded toString in the AbstractMap useful.

Now, to address the question:

You can use a LinkedHashMap. A Linked Hash Map is a map that also has a doubly linked list. The linked list maintains the entries in insertion order.

Although you want to iterate through the contents of the Map Objects, the LinkedHashMap API doe not offer a get(int index) or other method that supports iteration using a for loop. Neither does it directly offer an iterator method.

But, it does offer these methods:

  • public Set<Map.Entry<K,​V>> entrySet()
  • public Set<K> keySet()
  • public Collection<V> values()

Note that a Set is a type of Collection. And a Collection is Iterable.

  • These methods return Collection views of the LinkedHashMap.
  • They don't copy the data from the Map to a new Set or new Collection Object.
  • They allow you to treat the Map as a Set or Collection.
  • Think of them as wrappers for your Map Objects.

Now that you know those methods exist, and can find the API documentation, how you want to use them is up to you. Here is one way, but it is in keeping with using Map<Character, Integer>:

public static boolean isIsomorphic(String s, String t) {      
        if (s.length() != t.length()) { return false; }
        LinkedHashMap <Character, Integer> smap = loadMap (s);
        LinkedHashMap <Character, Integer> tmap = loadMap (t);
        if (smap.size() != tmap.size()) { return false; }      
        Collection<Integer> tValues = tmap.values();
        Collection<Integer> sValues = smap.values ();
        List<Integer> tList = new ArrayList<> ();
        tList.addAll(tValues);
        List<Integer> sList = new ArrayList<> ();
        sList.addAll (sValues);
        return sList.equals(tList);
    }

Note: I addressed only the question of sequentially comparing contents of a pair of HashMaps. If my understanding of the Isomorphic Strings problem is correct, this code will produce false positives. That is, it may identify a pair of Strings as isomorphic when they are not strictly isomorphic. I'll leave it to you to figure out why, to find an example of false positives.

1
WJS On

I would just use one map and a set to determine if they are isomorphic.

  • first check the lengths of the strings as they should be the same.
  • if not, they cannot be isomorphic as at least one char in one string would not map to the same (or any character) in the other string.
  • if the are the same length, the use a set to contain all the mappings of a given character. If any set exceeds length of 1, then the strings are not isomorphic since more than one mapping for a given character exists.
   public static boolean isIsomorphic(String s1, String s2) {
        Map<String, Set<String>> map = new HashMap<>();
        if (s1.length() != s2.length()) {
            return false;
        }
        for (int i = 0; i < s1.length(); i++) {
           String c = s1.substring(i,i+1);
           map.computeIfAbsent(c, v-> new HashSet<>()).add(s2.substring(i,i+1));
           if (map.get(c).size() > 1) {
               return false;
           }
        }
        return true;
    }