Collectors.groupingBy() 中的映射值

Map values in Collectors.groupingBy()

为了这个例子,假设我有一个简单的类型 Tuple,它有两个属性:

interface Tuple<T, U> {
    T getFirst();
    U getSecond();
}

现在我想将 (first, second) 元组的集合转换为一个映射,该映射将每个 first 值映射到具有该特定 [= 的元组中包含的一组所有 second 值16=] 值。方法 groupSecondByFirst() 显示了一种可能的实现方式,可以执行我想要的操作:

<T, U> Map<T, Set<U>> groupSecondByFirst(Set<Tuple<T, U>> tuples) {
    Map<T, Set<U>> result = new HashMap<>();

    for (Tuple<T, U> i : tuples) {
        result.computeIfAbsent(i.getFirst(), x -> new HashSet<>()).add(i.getSecond());
    }

    return result;
}

如果输入是 [(1, "one"), (1, "eins"), (1, "uno"), (2, "two"), (3, "three")] 输出将是 { 1 = ["one", "eins", "uno"], 2 = ["two"], 3 = ["three"] }

我想知道是否以及如何使用流框架实现它。我得到的最好的是以下表达式,其中 returns 一个包含完整元组作为值的映射,而不仅仅是它们的 second 元素:

Map<T, Set<Tuple<T, U>>> collect = tuples.stream().collect(
    Collectors.groupingBy(Tuple::getFirst, Collectors.toSet()));

我找到了解决办法;它涉及Collections.mapping(),它可以包装一个收集器并在流上应用映射函数以向包装的收集器提供元素:

static <T, U> Map<T, Set<U>> groupSecondByFirst(Collection<Tuple<T, U>> tuples) {
    return tuples
        .stream()
        .collect(
            Collectors.groupingBy(
                Tuple::getFirst,
                Collectors.mapping(
                    Tuple::getSecond,
                    Collectors.toSet())));
}