将整个地图转换/展平以列出最有效的方法(键和值放在一起,而不是分开)



我需要转换以下内容:

Map<Long,Map<String,String>> mapOfMaps

List<List<String>> listOflists

其中外部映射(mapOfMaps(的键是冗余的(对于该操作(。所以基本上,我可以从mapOfMaps.values().stream()开始。

对于每个地图对象,例如:

{"苹果":"1","橙色":"2"}

我需要将其转换为列表:

{"苹果"、"1"、"橙色"、"2"}

最有效的方法是什么?

完整示例:

{"1L":{"key1":"value1","key2":"value2"},"2L":{"key3":"value3","key4":"value4"}}

预期:

[[key1,value1,key2,value2],[key3,value3,key4,value4]]

类似这样的东西:

List<List<String>> listOflists =
mapOfMaps.values()
.stream()
.map(m -> m.entrySet()
.stream()
.flatMap(e->Stream.of(e.getKey(),e.getValue()))
.collect(Collectors.toList()))
.collect(Collectors.toList());

对于每个内部Map,您可以在entrySet()上进行流式传输,并创建一个包含所有键和值的流,将这些键和值收集到List中。

例如,如果使用初始化Map

Map<Long,Map<String,String>> mapOfMaps = new HashMap<>();
mapOfMaps.put(1L,new HashMap());
mapOfMaps.put(2L,new HashMap());
mapOfMaps.get(1L).put("key1","value1");
mapOfMaps.get(1L).put("key2","value2");
mapOfMaps.get(2L).put("key3","value3");
mapOfMaps.get(2L).put("key4","value4");

您将获得以下List:

[[key1, value1, key2, value2], [key3, value3, key4, value4]]

下面是我的解决方案版本。您可以对条目进行迭代,并相应地将值添加到所需的列表中。

List<List<String>> list = map.
values()
.stream()
.map(value -> {
List<String> list1 = new ArrayList<>();
for (Map.Entry<String, String> entry : value.entrySet()) {
list1.add(entry.getKey());
list1.add(entry.getValue());
}
return list1;
})
.collect(Collectors.toList());

测试输入:


Map<Long, Map<String, String>> map = new HashMap<>();
Map<String, String> submap1 = new HashMap<>();
submap1.put("test", "test2");
Map<String, String> submap2 = new HashMap<>();
submap2.put("test6", "6");
map.put(1l, submap1);
map.put(2l, submap2);

这里有一个解决方案,它比嵌套的lambdas稍微不那么酷,但可读性更强:

public static void main(String[] args) {
// create a result list
List<List<String>> resultList = new ArrayList<>();
// create some try-out values
// a source map
Map<Long,Map<String,String>> mapOfMaps = new HashMap<>();
// some sub maps
Map<String, String> subMapOne = new HashMap<>();
subMapOne.put("One", "1");
subMapOne.put("Two", "2");
subMapOne.put("Three", "3");
Map<String, String> subMapTwo = new HashMap<>();
subMapTwo.put("Two", "2");
Map<String, String> subMapThree = new HashMap<>();
subMapThree.put("One", "1");
subMapThree.put("Three", "3");
mapOfMaps.put(1l, subMapOne);
mapOfMaps.put(2l, subMapTwo);
mapOfMaps.put(3L, subMapThree);
// just nest two forEach-calls
mapOfMaps.forEach((key, value) -> {
// create a new list for each submap
List<String> subList = new ArrayList<>();
value.forEach((subKey, subValue) -> {
// and add each entry of the submap to it
subList.add(subKey);
subList.add(subValue);
});
// finally add the list to the result list
resultList.add(subList);
});
resultList.forEach(System.out::println);
}

输出为

[One, 1, Two, 2, Three, 3]
[Two, 2]
[One, 1, Three, 3]

如果您对使用第三方库持开放态度,那么以下内容将使用Eclipse集合:

@Test
public void mapOfMapsToListOfLists()
{
MutableMap<Long, MutableSortedMap<String, String>> map = Maps.mutable.with(
1L, SortedMaps.mutable.with("key1", "value1", "key2", "value2"),
2L, SortedMaps.mutable.with("key3", "value3", "key4", "value4"));
MutableList<MutableList<String>> listOfLists = map.valuesView()
.collect(innerMap -> innerMap.keyValuesView()
.flatCollect(this::pairToList).toList())
.toList();
List<List<String>> expected = Lists.mutable.with(
Lists.mutable.with("key1", "value1", "key2", "value2"),
Lists.mutable.with("key3", "value3", "key4", "value4"));
Assert.assertEquals(expected, listOfLists);
}
public ImmutableList<String> pairToList(Pair<String, String> pair)
{
return Lists.immutable.with(pair.getOne(), pair.getTwo());
}

我将内部映射初始化为SortedMaps,以保证测试中调用Assert.assertEquals时密钥的顺序。我上面使用的接口类型来自Eclipse Collections,并扩展了JDK接口类型(例如MutableMap扩展了Map,MutableList扩展了List(,但您也可以使用带有静态实用程序的JDK类型,如下所示:

@Test
public void jdkMapOfMapsToListOfLists()
{
Map<Long, Map<String, String>> map = Maps.mutable.with(
1L, SortedMaps.mutable.with("key1", "value1", "key2", "value2"),
2L, SortedMaps.mutable.with("key3", "value3", "key4", "value4"));
List<List<String>> listOfLists = MapIterate.collect(map,
innerMap -> Iterate.flatCollect(
innerMap.entrySet(),
this::entryToList,
new ArrayList<>()));
List<List<String>> expected = Arrays.asList(
Arrays.asList("key1", "value1", "key2", "value2"),
Arrays.asList("key3", "value3", "key4", "value4"));
Assert.assertEquals(expected, listOfLists);
}
public List<String> entryToList(Map.Entry<String, String> entry)
{
return Arrays.asList(entry.getKey(), entry.getValue());
}

注意:我是Eclipse Collections 的提交人

最新更新