2016-05-26 32 views
7

Bei einem Map<String, Object>, in dem die Werte entweder String oder ein anderer Map<String, Object> sind, wie würde man mit Java 8 die Maps auf eine einzige Liste von Werten reduzieren?Rekursiv Werte von verschachtelten Maps in Java reduzieren 8

Beispiel:

Map - "key1" -> "value1" 
    - "key2" -> "value2" 
    - "key3" -> Map - "key3.1" -> "value3.1" 
        - "key3.2" -> "value3.2" 
        - "key3.3" -> Map - "key3.3.1" -> "value3.3.1" 
             - "key3.3.2" -> "value3.3.2" 

Für das obige Beispiel würde Ich mag die folgende Liste:

value1 
value2 
value3.1 
value3.2 
value3.3.1 
value3.3.2 

Ich weiß, es kann wie folgt geschehen:

public static void main(String args[]) throws Exception { 
    //Map with nested maps with nested maps with nested maps with nested...... 
    Map<String, Object> map = getSomeMapWithNestedMaps(); 

    List<Object> values = new ArrayList<>(); 
    addToList(map, values); 

    for (Object o:values) { 
     System.out.println(o); 
    } 
} 

static void addToList(Map<String, Object>map, List<Object> list) { 
    for (Object o:map.values()) { 
     if (o instanceof Map) { 
      addToList((Map<String, Object>)o, list); 
     } else { 
      list.add(o); 
     } 
    } 
} 

Wie kann Ich mache das mit einer Stream?

Edit:

Nach einigen Herumspielen ich es herausgefunden:

public static void main(String args[]) throws Exception { 
    //Map with nested maps with nested maps with nested maps with nested...... 
    Map<String, Object> map = getSomeMapWithNestedMaps(); 
    //Recursively flatten maps and print out all values 
    List<Object> list= flatten(map.values().stream()).collect(Collectors.toList()); 
} 

static Stream<Object> flatten(Stream<Object> stream) { 
    return stream.flatMap((o) -> 
     (o instanceof Map) ? flatten(((Map<String, Object>)o).values().stream()) : Stream.of(o) 
    ); 
} 
+1

http://stackoverflow.com/questions/21646683/recursive-stream schlägt vor, eine Methodenreferenz zu verwenden. – jaco0646

Antwort

12

Sie könnten eine rekursive Methode definieren, die eine Karte abflacht und als Funktion für Stream#flatMap verwenden oder verwenden Sie es durch Aufruf direkt.

Beispiel:

public class FlatMap { 

    public static Stream<Object> flatten(Object o) { 
     if (o instanceof Map<?, ?>) { 
      return ((Map<?, ?>) o).values().stream().flatMap(FlatMap::flatten); 
     } 
     return Stream.of(o); 
    } 

    public static void main(String[] args) { 
     Map<String, Object> map0 = new TreeMap<>(); 
     map0.put("key1", "value1"); 
     map0.put("key2", "value2"); 
     Map<String, Object> map1 = new TreeMap<>(); 
     map0.put("key3", map1); 
     map1.put("key3.1", "value3.1"); 
     map1.put("key3.2", "value3.2"); 
     Map<String, Object> map2 = new TreeMap<>(); 
     map1.put("key3.3", map2); 
     map2.put("key3.3.1", "value3.3.1"); 
     map2.put("key3.3.2", "value3.3.2"); 

     List<Object> collect = map0.values().stream().flatMap(FlatMap::flatten).collect(Collectors.toList()); 
     // or 
     List<Object> collect2 = flatten(map0).collect(Collectors.toList()); 
     System.out.println(collect); 
    } 
} 

Für die verschachtelte Karte gegeben, druckt es

[Wert1, Wert2, value3.1, value3.2, value3.3.1, value3.3.2]

+0

Fantastisch! Ich habe es nach einer Weile herausgefunden, überprüfe meine aktualisierte Frage! – Ian2thedv