如题,已知如下结构:
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
))
);
怎么转换比较方便呢?
###本来想不劳而获的,算了自己写把
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()
,不但没有什么性能优势,反而会更慢。