繁体   English   中英

订购 Map<string, integer> 按列表<string>使用流</string></string,>

[英]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中呈现的数据进行排序可以以两种模式实现:

  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);

Output:

{a=0, e=4, o=5, b=1, d=7}

它类似于orderSequencenonOrderedData之间的INNER JOIN

  1. 如果在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}

它类似于orderSequencenonOrderedData之间的LEFT JOIN


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

但是,以下两个代码示例在 stream 执行之外修改了 nonOrderedData 的nonOrderedData

  1. 保留来自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}

它类似于orderSequencenonOrderedData之间的RIGHT JOIN

  1. 保留orderSequencenonOrderedData中的所有值,类似于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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM