2016-05-26 10 views
7

Dato un Map<String, Object>, dove i valori sono o String o un altro Map<String, Object>, in che modo uno, utilizzando Java 8, appiattisce le mappe in un unico elenco di valori?Appiattisci in modo ricorsivo i valori delle mappe nidificate in Java 8

Esempio:

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" 

Per l'esempio di cui sopra, vorrei il seguente elenco:

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

so che può essere fatto in questo modo:

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); 
     } 
    } 
} 

Come può Lo faccio con uno Stream?

Edit:

Dopo un po 'di gioco intorno ho capito:

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 suggerisce di utilizzare un riferimento al metodo. – jaco0646

risposta

12

è possibile definire un metodo ricorsivo che appiattisce una mappa e usarlo come una funzione per Stream#flatMap o usarlo chiamandolo direttamente.

Esempio:

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); 
    } 
} 

Per la data carta nidificato, stampa

[valore1, valore2, value3.1, value3.2, value3.3.1, value3.3.2]

+0

Fantastico! In realtà l'ho capito dopo un po ', controlla la mia domanda aggiornata! – Ian2thedv

Problemi correlati