java8数据结构优雅的转换方式

如题,已知如下结构:

map的大小不确定,但是 map中的v(也就是list)的大小都是一致的。

Map<String, List<Object>> map = new HashMap<>(ImmutableMap.of(
                "a", Lists.newArrayList(1, 2, 3),
                "b", Lists.newArrayList(4, 5, 6)
        ));

要转换成如下结构:

List<Map<String, Object>> list = Lists.newArrayList(
                Maps.newHashMap(ImmutableMap.of(
                        "a", 1,
                        "b", 4
                )),
                Maps.newHashMap(ImmutableMap.of(
                        "a", 2,
                        "b", 5
                )),
                Maps.newHashMap(ImmutableMap.of(
                        "a", 3,
                        "b", 6
                ))
        );

怎么转换比较方便呢?

阅读 3.1k
2 个回答

本来想不劳而获的,算了自己写把

int total = map.values().iterator().next().size();
        List<Map<String, Object>> list = IntStream.range(0, total)
                .boxed()
                .parallel()
                .map(i -> map.entrySet()
                        .stream()
                        .reduce(new HashMap<>(total), (accMap, entry) -> {
                            accMap.put(entry.getKey(), entry.getValue().get(i));
                            return accMap;
                        }, (BinaryOperator<Map<String, Object>>) (accMap1, accMap2) -> {
                            accMap1.putAll(accMap2);
                            return accMap1;
                        }))
                .collect(Collectors.toList());

如果用库:abacus-util

// 这里取value的最大size,假设它们的size可能不一样
int maxValueSize = Stream.ofValues(map).mapToInt(it -> it.size()).max().orZero();

List<Map<String, Object>> list = IntStream.range(0, maxValueSize)
        .mapToObj(it -> Stream.of(map).filter(e -> e.getValue().size() > it).toMap(e -> e.getKey(), e -> e.getValue().get(it)))
        .toList();

如果以后可能需要重用这个代码,也可以准备一个方法:

public static <K, V> List<Map<K, V>> flatToMap(final Map<K, ? extends List<? extends V>> map) {
    if (map == null) {
        return new ArrayList<>();
    }

    int maxValueSize = 0;

    for (List<? extends V> v : map.values()) {
        maxValueSize = N.max(maxValueSize, N.size(v));
    }

    final List<Map<K, V>> result = new ArrayList<>(maxValueSize);

    for (int i = 0; i < maxValueSize; i++) {
        final Map<K, V> m = new HashMap<>();

        for (Map.Entry<K, ? extends List<? extends V>> entry : map.entrySet()) {
            if (entry.getValue() != null || entry.getValue().size() > i) {
                m.put(entry.getKey(), entry.getValue().get(i));
            }
        }

        result.add(m);
    }

    return result;
}

这样代码就可以简化为:

Stream.of(map).map(it -> flatToMap(it)).findFirst().orElseThrow();

最后,一个建议,想着这样的轻操作,没有必要用parallel(),不但没有什么性能优势,反而会更慢。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题