2016-05-26 3 views
7

Учитывая Map<String, Object>, где значения являются либо String, либо еще Map<String, Object>, как один, используя Java 8, сгладить карты до одного списка значений?Рекурсивно Сгладить значения вложенных карт в Java 8

Пример:

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" 

Для приведенного выше примера, я хотел бы следующий список:

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

Я знаю, что это можно сделать так:

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

Как может Я делаю это с помощью Stream?

Edit:

После некоторого игры вокруг я понял это:

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 предлагает использовать ссылку на метод. – jaco0646

ответ

12

Вы можете определить рекурсивный метод, который уплощается одну карту и использовать его в качестве функции для Stream#flatMap или использовать его, называя его непосредственно.

Пример:

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

Для данной вложенной карте, он печатает

[значение1, значение2, value3.1, value3.2, value3.3.1, value3.3.2]

+0

Фантастический! Я действительно понял это через некоторое время, проверьте мой обновленный вопрос! – Ian2thedv

Смежные вопросы