在Collectors.groupingBy()中映射值

时间:2015-06-22 14:48:43

标签: java functional-programming java-8 java-stream

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

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

现在,我想将(first, second)元组的集合转换为一个映射,该映射将每个first值映射到包含在具有该特定{{1}的元组的所有second值中价值。方法first显示了实现我想要的可能实现:

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")]

我想知道是否以及如何使用streams框架实现这一点。我得到的最好的是以下表达式,它返回一个包含完整元组作为值的地图,而不仅仅是它们的{ 1 = ["one", "eins", "uno"], 2 = ["two"], 3 = ["three"] }元素:

second

1 个答案:

答案 0 :(得分:33)

我找到了解决方案;它涉及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())));
}