使用流按 List<String> 对 Map<String, Integer> 进行排序

Pol*_*oli 1 java sorting collections treemap java-stream

Map<String, Integer> nonOrderedData = // {b=1, c=2, d=3, e=4, a=0}
List<String> orderSequence = // a, b, c, d, e
Run Code Online (Sandbox Code Playgroud)

我需要应用顺序序列来获取正确排序的数据,我如何使用(首选)流实现这一点?

我使用的是非流方式:

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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

想要更清洁的方式来实现我想要的。


我注意到在我的方法中我可以只返回new TreeMap<>(nonOrderedData)并且它会工作得很好,但我不想坚持只应用 asc 顺序 - 我想读取实际序列值然后更改nonOrderedData.

Ale*_*nko 5

HashMap不能用于存储orderedData,因为它不保证其键的顺序,所以LinkedHashMap应使用哪个维护插入顺序。

通过orderSequence使用流中呈现的数据进行排序可以通过两种模式实现:

  1. 仅保留 中可用的值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);
Run Code Online (Sandbox Code Playgroud)

输出:

{a=0, e=4, o=5, b=1, d=7}
Run Code Online (Sandbox Code Playgroud)

它类似于INNER JOIN之间orderSequencenonOrderedData

  1. reorderedData如果在orderSequence中缺少from 键,则填充一些默认值nonOrderedData
{a=0, e=4, o=5, b=1, d=7}
Run Code Online (Sandbox Code Playgroud)

输出:

{a=0, e=4, i=-1, o=5, u=-1, b=1, c=-1, d=7}
Run Code Online (Sandbox Code Playgroud)

它类似于LEFT JOIN之间orderSequencenonOrderedData


更新
在上述实现中nonOrderedData,与 中的键不匹配的键值对orderSequence被完全跳过。可以reordered使用Map::remove (Object key)返回要删除的键的值来跟踪此类键(并稍后添加到结果中)。

但是,以下两个代码示例修改nonOrderedData了流执行之外的状态。

  1. 保持键和相关的值nonOrderedData,并将非配对到最后:
Map<String, Integer> reorderedWithDefault = orderSequence
    .stream()
    .collect(Collectors.toMap(
        key -> key, nonOrderedData.getOrDefault(key, -1), 
        (v1, v2) -> v1, LinkedHashMap::new
    ));
    
System.out.println(reorderedWithDefault);
Run Code Online (Sandbox Code Playgroud)

输出:

remained: {f=5, q=6, z=8}
{a=0, e=4, b=1, d=7, f=5, q=6, z=8}
Run Code Online (Sandbox Code Playgroud)

它类似于RIGHT JOIN之间orderSequencenonOrderedData

  1. 保留两者的所有值orderSequence并且nonOrderedData类似于FULL JOIN

这里将为未映射的键提供默认值 inorderSequence和不匹配的键 fromnonOrderedData将添加到末尾。

{a=0, e=4, i=-1, o=5, u=-1, b=1, c=-1, d=7}
Run Code Online (Sandbox Code Playgroud)

输出:

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}
Run Code Online (Sandbox Code Playgroud)