1

I have a map of maps as follows:- myMap = {cfds2={fname=ck1, uname=jk1, tenant=ABC1}, cfds1={fname=ck, uname=jk, tenant=ABC}} and expecting a returned map as :- {tenant={fname=ck, handler=cfds1, uname=jk, tenant=ABC}} when getIoiProperties(String tenant) is being called with ABC. So Create a new map by using one of the key of the inner map to be key of a newly created map and key of the outer map becomes one of the values.

import com.google.common.collect.Maps;
import java.util.Map;

public class MapTest
{
   public Map<String, Map<String, String>> getIoiProperties(String tenant) 
  {
    Map<String, String> tenantMap = Maps.newHashMap();
    tenantMap.put("tenant", "ABC");
    tenantMap.put("uname", "jk");
    tenantMap.put("fname", "ck");
    //Map of Maps
    Map<String, Map<String, String>> myMap = Maps.newHashMap();
    myMap.put("cfds1", tenantMap);

    Map<String, String> tenantMap1 = Maps.newHashMap();
    tenantMap1.put("tenant", "ABC1");
    tenantMap1.put("uname", "jk1");
    tenantMap1.put("fname", "ck1");

    myMap.put("cfds2", tenantMap1);

    System.out.println("myMap = " + myMap);

    Map<String, Map<String, String>> result = Maps.newHashMap();
    //iterate map
    for (Map.Entry<String, Map<String, String>> entry : myMap.entrySet()) {
        String key = entry.getKey();
        for (Map.Entry<String, String> entry1 : entry.getValue().entrySet())
            if (entry1.getKey().equals("tenant") && entry1.getValue().equals(tenant)) {
                entry.getValue().put("handler", key);
                result.put(entry1.getKey(), entry.getValue());
            }
    }

    System.out.println(result);
    System.out.println("myMap = " + myMap);
    return result;
}

public static void main(String[] args) {
    MapTest mp = new MapTest();
    Map<String, Map<String, String>> res = mp.getIoiProperties("ABC");
    System.out.println(res.get("tenant"));
}

}

  • 1
    You should create a `class Something` with properties `tenant`, `uname`, and `fname`. – chrylis -cautiouslyoptimistic- Feb 23 '20 at 04:13
  • I honestly do not understand what you are trying to ask. – hfontanez Feb 23 '20 at 04:32
  • @JagdishAswani The best way to do this is have a POJO class with the properties as suggested by Chrylis. Then you can form a map like `Map` won't this solve your problem ? – Trishul Singh Choudhary Feb 23 '20 at 04:44
  • @hfontanez Consider I have a Map> like following :- {cfds1={fname=ck, uname=jk, tenant=ABC}} where **cfds1** is key and value is another Map. Now I want to create a new Map> where **tenant** one of the key of the inner map becomes the key for new map and the rest of values from the inner map along with the value of the outer map key are values of the newly created map. {*ABC* ={fname=ck, uname=jk, handler = **cfds1**}} – Jagdish Aswani Feb 23 '20 at 04:46
  • Added code works(except 2 minor issues) fine when running as standalone, however, throws ConcurrentModificationException when deployed as part of an application. Looking for Java 8 or Guava (ex:- BiMap) solutions. – Jagdish Aswani Feb 23 '20 at 06:36

3 Answers3

0

Before reading my algorithm, note that I did not check if the conditionals in the for loops work properly, that is on you. However, if they are alright, it should work perfectly.

Map<String, Map<String, String>> result = Maps.newHashMap();

for (Map.Entry<String, Map<String, String>> entry : myMap.entrySet()) {
    Map<String, String> handlerMap = Maps.newHashMap();
    handlerMap.put("handler", entry.getKey());
    boolean save = false;

    for (Map.Entry<String, String> entry1 : entry.getValue().entrySet())
        if (entry1.getKey().equals("tenant")){
            if (entry1.getValue().equals(tenant){
                save = true;
            }
        }
        handlerMap.put(entry1.getKey(), entry1.getValue());   
    }
    if (save){
        result.put("tenant", handlerMap);
        breaK; // Since there is just 1 tenant x handler, I stop the loop
    }
 }
  • Thanks for your reply. The output is not as expected, the other two key-value pairs are missing from output: myMap = {cfds2={fname=ck1, uname=jk1, tenant=ABC1}, cfds1={fname=ck, uname=jk, tenant=ABC}} {tenant={handler=cfds1, cfds1=ABC}} {tenant={handler=cfds1, cfds1=ABC}} – Jagdish Aswani Feb 23 '20 at 06:25
0

Please check the below code

public Map<String, Map<String, String>> getIoiProperties(String tenant)
    {
        Map<String, String> tenantMap = new HashMap<>();
        tenantMap.put("tenant", "ABC");
        tenantMap.put("uname", "jk");
        tenantMap.put("fname", "ck");
        //Map of Maps
        Map<String, Map<String, String>> myMap =new HashMap<>();
        myMap.put("cfds1", tenantMap);

        Map<String, String> tenantMap1 = new HashMap<>();
        tenantMap1.put("tenant", "ABC1");
        tenantMap1.put("uname", "jk1");
        tenantMap1.put("fname", "ck1");

        myMap.put("cfds2", tenantMap1);

        System.out.println("myMap = " + myMap);

        Map<String, Map<String, String>> result = new HashMap<>();
        //iterate map
        for (Map.Entry<String, Map<String, String>> entry : myMap.entrySet()) {
            String key = entry.getKey();
            for (Map.Entry<String, String> entry1 : entry.getValue().entrySet())
                if (entry1.getKey().equals("tenant") && entry1.getValue().equals(tenant)) {
                    entry.getValue().put("handler", key);
                    result.put(entry1.getValue(), entry.getValue());
                    result.get(tenant).remove("tenant");
                }
        }

        System.out.println(result);
        //System.out.println("myMap = " + myMap);
        return result;
    }

Two issues were there in your code

  1. "tenant" key not removed from the inner map

  2. Instead of result.put(entry1.getKey(), entry.getValue()); result.put(entry1.getValue(), entry.getValue()); should be used.

dassum
  • 4,727
  • 2
  • 25
  • 38
  • Thanks for your reply and I spotted both the issue you mentioned. The code I added in my question is working when I run it as standalone, however, fails when deployed as part of an application:- java.util.ConcurrentModificationException: null at java.util.HashMap$HashIterator.nextNode(HashMap.java:1442) at java.util.HashMap$EntryIterator.next(HashMap.java:1476) at java.util.HashMap$EntryIterator.next(HashMap.java:1474) – Jagdish Aswani Feb 23 '20 at 06:29
  • please share the stack trace. – dassum Feb 23 '20 at 07:27
0

As you said, the previous code by dassum worked. Based on that, I decided to improve it to try to make it work. So, what is happening is that entry.getValue().put("handler", key); cannot be done while iterating. You can't modify the entry, as another thread is iterating over it; which throws the ConcurrentModificationException. So here's a way to solve it, I reused some of the code proportioned by erickson. What I did is create another map outside the loop to store the data that will be returned. Then, I merge both the previous and stored data. I hope this time it works.

 public Map<String, Map<String, String>> getIoiProperties(String tenant)
{
    Map<String, String> tenantMap = new HashMap<>();
    tenantMap.put("tenant", "ABC");
    tenantMap.put("uname", "jk");
    tenantMap.put("fname", "ck");
    //Map of Maps
    Map<String, Map<String, String>> myMap =new HashMap<>();
    Map<String, Map<String, String>> store =new HashMap<>();
    myMap.put("cfds1", tenantMap);

    Map<String, String> tenantMap1 = new HashMap<>();
    tenantMap1.put("tenant", "ABC1");
    tenantMap1.put("uname", "jk1");
    tenantMap1.put("fname", "ck1");

    myMap.put("cfds2", tenantMap1);

    System.out.println("myMap = " + myMap);

    Map<String, Map<String, String>> result = new HashMap<>();
    //iterate map
    for (Map.Entry<String, Map<String, String>> entry : myMap.entrySet()) {
        String key = entry.getKey();
        for (Map.Entry<String, String> entry1 : entry.getValue().entrySet())
            if (entry1.getKey().equals("tenant") && entry1.getValue().equals(tenant)) {
                store.put("handler", key);
                result.put(entry1.getValue(), entry.getValue());
                result.get(tenant).remove("tenant");
            }
    }
    Map<String, Map<String, String>> tmp =new HashMap<>(store);
    tmp.keySet().removeAll(result.keySet());
    result.putAll(tmp);
    store.forEach(target::putIfAbsent);

    System.out.println(result);
    //System.out.println("myMap = " + myMap);
    return result;
}