[英]Using Java 8 streams, how to transform Map<String, Map<String, List<Person>>> to Map<Integer, Map<String, Integer>>?
[英]Ordering Map<String, Integer> by List<String> using streams
Map<String, Integer> nonOrderedData = // {b=1, c=2, d=3, e=4, a=0}
List<String> orderSequence = // a, b, c, d, e
我需要应用订单序列来获取正确排序的数据,我如何使用(首选)stream 来实现这一点?
我使用的是非 stream 方式:
Map<String, Integer> orderedData = new HashMap<>();
for (Map.Entry<String, Integer> nod : nonOrderedData.entrySet()) {
for (String os : orderSequence) {
if (os == nod.getKey()) {
// add nonOrderedData data
} else {
// add data by sequence
}
}
}
想要更清洁的方式来满足我的需求。
我注意到在我的方法中我可以只返回new TreeMap<>(nonOrderedData)
并且它可以正常工作,但我不想坚持只应用 asc 顺序 - 我想读取实际的序列值然后更改nonOrderedData
。
HashMap
不能用于存储orderedData
,因为它不保证其键的顺序,因此应使用保持插入顺序的LinkedHashMap
。
使用流对orderSequence
中呈现的数据进行排序可以以两种模式实现:
nonOrderedData
中可用的值:Map<String, Integer> nonOrderedData = Map.of(
"b", 1, "e", 4, "a", 0, "o", 5, "d", 7
);
List<String> orderSequence = Arrays.asList(
"a", "e", "i", "o", "u", "b", "c", "d"
);
Map<String, Integer> reordered = orderSequence
.stream()
.filter(nonOrderedData::containsKey)
.collect(Collectors.toMap(
key -> key, nonOrderedData::get,
(v1, v2) -> v1, LinkedHashMap::new
));
System.out.println(reordered);
Output:
{a=0, e=4, o=5, b=1, d=7}
它类似于orderSequence
和nonOrderedData
之间的INNER JOIN
。
orderSequence
中缺少nonOrderedData
reorderedData
Map<String, Integer> reorderedWithDefault = orderSequence
.stream()
.collect(Collectors.toMap(
key -> key, nonOrderedData.getOrDefault(key, -1),
(v1, v2) -> v1, LinkedHashMap::new
));
System.out.println(reorderedWithDefault);
Output:
{a=0, e=4, i=-1, o=5, u=-1, b=1, c=-1, d=7}
它类似于orderSequence
和nonOrderedData
之间的LEFT JOIN
。
更新
在上述实现中, orderSequence
nonOrderedData
的键不匹配的键值对被完全跳过。 可以使用Map::remove (Object key)
跟踪此类键(并稍后添加到reordered
的结果中),该键返回被删除键的值。
但是,以下两个代码示例在 stream 执行之外修改了 nonOrderedData 的nonOrderedData
。
nonOrderedData
的键和相关值,将不匹配的对放在末尾:Map<String, Integer> nonOrderedData = new HashMap<>(Map.of(
"b", 1, "e", 4, "z", 8, "a", 0, "q", 6,
"f", 5, "d", 7
));
List<String> orderSequence = Arrays.asList("a", "e", "i", "o", "u", "b", "c", "d");
Map<String, Integer> reordered = orderSequence
.stream()
.filter(nonOrderedData::containsKey)
.collect(Collectors.toMap(
key -> key, nonOrderedData::remove,
(v1, v2) -> v1, LinkedHashMap::new
));
SortedMap<String, Integer> remainder = new TreeMap<>(nonOrderedData);
System.out.println("remained: " + remainder);
reordered.putAll(remainder);
System.out.println(reordered);
Output:
remained: {f=5, q=6, z=8}
{a=0, e=4, b=1, d=7, f=5, q=6, z=8}
它类似于orderSequence
和nonOrderedData
之间的RIGHT JOIN
。
orderSequence
和nonOrderedData
中的所有值,类似于FULL JOIN
这里将为nonOrderedData
中的非映射键提供默认值,并将orderSequence
中的非匹配键添加到末尾。
Map<String, Integer> reorderedFull = orderSequence
.stream()
.peek(key -> nonOrderedData.computeIfAbsent(key, (k) -> -1)) // default value
.collect(Collectors.toMap(
key -> key, nonOrderedData::remove,
(v1, v2) -> v1, LinkedHashMap::new
));
SortedMap<String, Integer> remainderFull = new TreeMap<>(nonOrderedData);
System.out.println("remained: " + remainderFull);
reorderedFull.putAll(remainderFull);
System.out.println(reorderedFull);
Output:
remained: {f=5, q=6, z=8}
{a=0, e=4, i=-1, o=-1, u=-1, b=1, c=-1, d=7, f=5, q=6, z=8}
如果您有一个有序的序列,您可以使用remove
方法收集一个新的 map,其中包含该序列中的键和无序 map中的值,该方法从该 Z1D78DC8ED51214E518B5114AE244 中删除键的映射,并返回前一个值FE249。
在收集到一个新的 map 后,如果无序的 map中还有一些东西,您可以使用putAll
方法添加这些条目。
Map<String, Integer> nonOrderedData = new HashMap<>(
Map.of("f", 5, "b", 1, "c", 2, "d", 3, "e", 4, "a", 0));
List<String> orderSequence = List.of("a", "b", "c", "d", "e");
Map<String, Integer> orderedMap = orderSequence.stream()
.collect(LinkedHashMap::new,
(col, e) -> col.put(e, nonOrderedData.remove(e)),
HashMap::putAll);
System.out.println(orderedMap); // {a=0, b=1, c=2, d=3, e=4}
System.out.println(nonOrderedData); // {f=5}
orderedMap.putAll(nonOrderedData); // add what's left
System.out.println(orderedMap); // {a=0, b=1, c=2, d=3, e=4, f=5}
同样,您可以收集map 条目列表,而不是map :
Map<String, Integer> nonOrderedData = new HashMap<>(
Map.of("f", 5, "b", 1, "c", 2, "d", 3, "e", 4, "a", 0));
List<String> orderSequence = List.of("a", "b", "c", "d", "e");
List<Map.Entry<String, Integer>> orderedList = orderSequence.stream()
.map(e -> Map.entry(e, nonOrderedData.remove(e)))
.collect(Collectors.toList());
System.out.println(orderedList); // [a=0, b=1, c=2, d=3, e=4]
System.out.println(nonOrderedData); // {f=5}
orderedList.addAll(nonOrderedData.entrySet()); // add what's left
System.out.println(orderedList); // [a=0, b=1, c=2, d=3, e=4, f=5]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.