在Java中的Map中爆炸列表

时间:2018-05-07 11:41:59

标签: java java-8

我想爆炸地图中的列表并将地图转换为地图列表。

例如:

我想以Map<String, Object>

格式转换下面的地图
{key1=message1, key2=message2, key3=[abc, xyz]} 

以下地图列表(即List<Map<String,String>>

[{key1=message1, key2=message2, key3=abc},{key1=message1, key2=message2, key3=xyz}]

最好的方法是什么,最好是在Java 8中?

到目前为止,我尝试过如下。但我知道这不是最好的方法。

package com.test;


import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Maptest {

    public static void main(String[] args){

        Map<String,Object> map = new HashMap<>();
        List<String> list = new ArrayList<>();

        List<Map<String,String>> listofMaps = new ArrayList<>();

        list.add("abc");
        list.add("xyz");

        map.put("key1","message1");
        map.put("key2","message2");
        map.put("key3",list);

        System.out.println(map);


        List<String> list1 = (ArrayList)map.get("key3");

        for(String s: list1){

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

            localMap.put("key1",(String)map.get("key1"));
            localMap.put("key2",(String)map.get("key2"));
            localMap.put("key3",s);

            listofMaps.add(localMap);

        }

        System.out.println(listofMaps);
    }
}

2 个答案:

答案 0 :(得分:1)

在给您解决方案之前,我必须提醒您:您应该考虑一下您的数据结构,应该避免在生产代码中使用此解决方案。这是非常糟糕的数据结构设计。

那就是说,这是解决方案:

private Stream<String> keysForLists(Map<String, Object> map) {
    // retrieve all keys which map to list values
    return map.keySet().stream()
       .filter(key -> List.class.isAssignableFrom(map.get(key).getClass()));
}

private boolean typecheck(Map<String, Object> map) {
    // check if there is really just one list value
    // and all the other values are strings
    return keysForLists(map).count() == 1
        && map.values().stream().map(o -> o.getClass())
            .filter(t -> t.equals(String.class)).count() == map.size() - 1;
}

public List<Map<String, String>> explode(Map<String, Object> map) {
    if (!typecheck(map)) {
        throw new ClassCastException(
            "Map values do not have the required types: one list plus arbitrarily many strings");
    }

    final String listKey = keysForLists(map).findFirst().get();
    final List<String> listValue = (List<String>)map.get(listKey);

    final List<Map<String, String>> result = new ArrayList<>();
    // for each list value create a new map
    listValue.forEach(value -> {
        final Map<String, String> m = new HashMap<>();
        // add the list value to the map
        m.put(listKey, value);
        // add all the other key/value pairs to the map
        map.keySet().stream().filter(k -> !k.equals(listKey))
            .forEach(k -> m.put(k, (String)map.get(k)));
        result.add(m);
    });

    return result;
}

答案 1 :(得分:1)

// map val to List<String>
Map<String, List<String>> tempMap = map.entrySet().stream().collect(Collectors.toMap(e -> e.getKey(),
        e -> (e instanceof ArrayList) ? (List<String>) e : (List<String>) Arrays.asList(e.toString())));
// get max
int max = tempMap.values().stream().mapToInt(e -> e.size()).max().orElse(0);

// create result
final List<Map<String, String>> result = new ArrayList<>();
for (int i = 0; i <= max; i++) {
    final Map<String, String> m = new HashMap<>();
    for (String key : map.keySet()) {
        String val = Optional.of(tempMap.get(key).get(i)).orElse(tempMap.get(key).get(i - 1));
        m.put(key, val);
    }
    result.add(m);
}