0

What do you think is the best way to find a value in a map inside another map.

    Map <String, String> map1 = new HashMap<>();

    map1.put("map1|1", "1.1");
    map1.put("map1|2", "1.2");
    map1.put("map1|3", "1.3");
    map1.put("map1|4", "1.4");

    Map <String, String> map2 = new HashMap<>();

    map2.put("map2|1", "2.1");
    map2.put("map2|2", "2.2");
    map2.put("map2|3", "2.3");
    map2.put("map2|4", "2.4");


    Map<String, Map> mapOfMaps = new HashMap<>();

    mapOfMaps.put("MAP|map1", map1);
    mapOfMaps.put("MAP|map2", map2);

Now if I need the value of "MAP|map2" (inside mapOfMaps) and "map2|3" (inside map2) will be "2.3"

I tried to do something like:

System.out.println("x="+getValue(mapOfMaps,"MAP|map2", "map2|4"));

public static String getValue (Map<String, Map> map,String mapfind, String val) {

     Map<Object, Object> mp = map.entrySet().stream()
                .filter(x -> x.getKey().equals(mapfind))
                .collect(Collectors.toMap(p -> p.getKey(), p -> p.getValue()));

     System.out.println("--------"+mp);

     return (String) mp.get(val);
 }

but the result is:

--------{MAP|map2={map2|1=2.1, map2|4=2.4, map2|2=2.2, map2|3=2.3}}
x=null

Can you help me with some ideas?

Timisorean
  • 1,388
  • 7
  • 20
  • 30
Lubelmont
  • 7
  • 2
  • 7

3 Answers3

3

Instead of declaring mapOfMaps by its raw type it should be defined as

Map<String, Map<String, String>> mapOfMaps = new HashMap<>();

The corresponding getValue method would look like this:

  public static String getValue(Map<String, Map<String, String>> mapOfMaps, String mapfind, String val) {
    Map<String, String> innerMap = mapOfMaps.get(mapfind);
    return innerMap != null ?
      innerMap.get(val) :
      null;
  }

Using Optional we can write it as follows:

  public static String getValue(Map<String, Map<String, String>> mapOfMaps, String mapfind, String val) {
    return Optional.ofNullable(mapOfMaps.get(mapfind))
      .map(m -> m.get(val))
      .orElse(null);
  }

If we kept mapOfMaps declared by its raw type we would get in the first version of getValue a type safety warning about an unchecked conversion and in the second version we would need explicitly cast the result to String. Since we use mapOfMaps only to map String keys to String values we should declare it accordingly.


Further reading: What is a raw type and why shouldn't we use it?

LuCio
  • 5,055
  • 2
  • 18
  • 34
0

I think the easiest way to get your desired output would be to use map.get(mapfind).get(val). But if you want to achieve it using your existing code, you could call values() on the collected map and call filter to get a second level filter. Below is the code snippet of your modified method

public static String getValue(Map<String, Map> map, String mapfind, String val) {
    Map mp = map.entrySet().stream().filter(x -> x.getKey().equals(mapfind))
            .collect(Collectors.toMap(p -> p.getKey(), p -> p.getValue()))

            .values().stream().filter(y -> y.containsKey(val)).findAny().orElse(null);

    System.out.println("--------" + mp);
    if (mp == null)
        return "";
    return (String) mp.get(val);
}
Ashishkumar Singh
  • 3,580
  • 1
  • 23
  • 41
-1
public static String getValue (Map<String, Map> map,String mapfind, String val) {
    Map childMap = map.get(mapfind);
    if (childMap == null) {
        return null;
    }
    return childMap.containsKey(val) ? childMap.get(val).toString() : null;
}
Tom Drake
  • 527
  • 5
  • 11
  • https://stackoverflow.com/questions/52227886/get-a-string-from-a-map-inside-map-java-8#comment91405344_52227886 – Naman Sep 07 '18 at 18:40
  • At least replace `findMap` by `mapfind` so your code can be compiled. – LuCio Sep 07 '18 at 18:44