给定一个函数和一组参数,是否有一种简单的方法来创建反向映射?

Is there a brief way to create a reverse mapping given a function and a set of arguments?

假设我们有一个将 X 映射到 Y 的纯方法:

public abstract Y map(X x);

是否有任何简短的方法来创建从函数到映射到这些函数的参数集的反向映射?也就是说,从 Set<X> 创建 Map<Y, Set<X>>。简而言之,我的意思是一个比直接方式更简洁的库解决方案:

public Map<Y, Set<X>> reverseMapping(Set<X> arguments) {
    Map<Y, Set<X>> answer = new HashMap<>();
    arguments.forEach(x->{
        Y y = map(x);
        if (!answer.containsKey(y)) {
            answer.put(y, new HashSet<>());
        }
        answer.get(y).put(x);
    });
    return answer;
}

Java8中增加了很多函数式编程的特性,我想可能会有我需要的。

这种任务有一个直接的解决方案,Collectors.groupingBy. While the single-argument version produces a Map<Y,List<X>, you can combine it with another Collector 产生 Sets

public Map<Y, Set<X>> reverseMapping(Set<X> arguments) {
    return arguments.stream()
        .collect(Collectors.groupingBy(this::map, Collectors.toSet()));
}
public abstract Y map(X x);

您也可以随时提供一个 Function 作为参数,这样编程模型会很好。

public <X, Y> Map<Y, Set<X>> reverseMapping(Set<X> arguments, Function<X, Y> fn) {
    return arguments.stream()
            .collect(
                    Collectors.groupingBy(
                            fn, // The "map" invocation
                            Collectors.toSet()));
}

@Test
public void testFn() {
    final Set<String> cities = 
        Stream.of("NYC", "Los Angeles", "San Fransisco")
              .collect(Collectors.toSet());

    final Map<String, Set<String>> reversed = 
        reverseMapping(cities, city -> mapState(city));

    System.out.println(reversed); // -> {NY=[NYC], California=[San Fransisco, Los Angeles]}

}

// This is one version of a "map"-method as provided by the OP
private String mapState(String city) {
    switch (city) {
        case "NYC":
            return "NY";
        case "Los Angeles":
        case "San Fransisco":
            return "California";
    }
    return "Unknown";
}

基本上,您可以提供自己的 map 方法作为 lambda。