简体   繁体   English

Java 8 拉姆达 Map<string, string> 至 Map <string, map<string, long> &gt;</string,></string,>

[英]Java 8 Lambdas Map<String, String> to Map<String, Map<String, Long>>

I have a service that returns a response and maps it to a Map<String, String> object我有一个返回响应并将其映射到Map<String, String> object的服务

After this I need to calculate the key of the new map and insert as well all the keys that appear plus how many times they do.在此之后,我需要计算新的 map 的密钥并插入所有出现的密钥以及它们执行的次数。

They key is calculated by getting the first character of the associated string.它们的键是通过获取关联字符串的第一个字符来计算的。

Key: A -> August/Air

Key: B -> Boat/Big

Example:例子:

Service response:服务响应:

{
    {
        "august",
        "red"
    },
    {
        "air",
        "red"
    },
    {
        "boat",
        "blue"
    },
    {
        "big",
        "red"
    }
}

Expected output:预期 output:

{
    "a" : {
        "red" : 2
    },

    "b" : {
        "blue" : 1,
        "red": 1
    }
}

I did this already in Java 7 but I would like to apply lambdas to this.我已经在 Java 7 中这样做了,但我想对此应用 lambdas。

Map<String, Map<String, AtomicLong>> map = new HashMap<>();

String key = ...
String value = ...

Response.incrementCount(key, value);

map.put(key, Response.count.get(key));

Response.java响应.java

public static Map<String, Map<String, AtomicLong>> count = new HashMap<>();

public static void incrementCount(String key, String value) {
    count.computeIfAbsent(key, k -> new HashMap<>());

    AtomicLong actual = count.get(key).get(value);
    Map<String, AtomicLong> stringAtomicLongMap = count.get(key);
    if (null == actual) {
        actual = new AtomicLong();
        stringAtomicLongMap.put(value, actual);
        count.put(key, stringAtomicLongMap);
    }
    actual.incrementAndGet();
}

Existing Map<String, String> map should be converted this way:现有Map<String, String> map应该这样转换:

  1. Group by the first character of key按key的第一个字符分组
  2. For values, group by value and count frequency对于值,按值和计数频率分组
static Map<String, Map<String, Long>> convert(Map<String, String> map) {
    return map.entrySet()
            .stream()
            .collect(Collectors.groupingBy(
                e -> e.getKey().substring(0, 1),
                LinkedHashMap::new, // (optionally) use to keep insertion order
                Collectors.groupingBy(
                    Map.Entry::getValue, Collectors.counting()
                )
            ));
}

Test:测试:

Map<String, String> map = Map.of(
    "august", "red",
    "air", "red",
    "boat", "blue",
    "big", "red"
);
Map<String, Map<String, Long>> result = convert(map);
    
result.forEach((k, v) -> System.out.printf("'%s': %s%n", k, v));

Output: Output:

'a': {red=2}
'b': {red=1, blue=1}

Here is solution using Stream API:这是使用 Stream API 的解决方案:

Map<String, Map<String, Long>> resultMap = map.entrySet().stream()
    .map(entry -> {
        String firstChar = entry.getKey().substring(0, 1);
        return new AbstractMap.SimpleEntry<>(firstChar, entry.getValue());
    })
    .collect(Collectors.groupingBy(
        Map.Entry::getKey,
        Collectors.groupingBy(Map.Entry::getValue, Collectors.counting())
    ));

What is actually happening:实际发生了什么:

  • Given entry is changed to have only the first char (but as String) to be they key of entry给定条目被更改为只有第一个字符(但作为字符串)作为它们的条目键
  • Such entries are grouped by the key (first char)此类条目按键(第一个字符)分组
  • If there are multiple values by this key - they are grouped by the entry value - and counting such values如果此键有多个值 - 它们按条目值分组 - 并计算这些值

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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