【发布时间】:2020-06-02 17:18:18
【问题描述】:
我最近偶然发现了一个有趣的 Stream 挑战,要求 创建一个 Java (8) 流,从输入文件中读取整数并生成一个映射,将数字映射到其对应的最小素因子。
到目前为止我的看法:
Map<Integer, String> map = Files.lines(Path.of("nums.txt")).filter(s -> Integer.parseInt(s) > 2).map(Integer::parseInt)
.collect(Collectors.toMap(i -> {
if(i == 2) return 2;
var divisors = IntStream.rangeClosed(2, i).filter(j -> i % j== 0).boxed()
.collect(Collectors.toList());
return divisors.stream().filter(integer -> {
for(int ii = 2; ii < Math.sqrt(integer); ii++) {
if(integer % ii == 0) return false;
}
return true;
}).findFirst().orElse(-1);
}, String::valueOf
, (s1, s2) -> s1 + ";" + s2));
现在没有合并 BiFunction 我会得到重复的键异常,所以为了避免我 从上面做了解决方法,它用分号连接类似的映射值。
我发现这种解决方案有点蹩脚,但我想知道,我的地图是否有可能有一个 Set 实现其第二个类型参数并将类似的映射值收集到一个集合中。
主要问题是如果例如。我在 KeyMapper 函数中实例化了新的 HashMap,它总是会为每个重复的键返回一个新的,因此两个 HashSet 的合并尝试总是徒劳的。
附注关于流本身的反馈也很受欢迎,我不确定这种方法是否过于复杂。
【问题讨论】:
-
假设文件包含
8 9 10 11,您给出的描述(“将数字映射到其对应的最小素数”)听起来结果应该是[8=2, 9=3, 10=2, 11=11],对吗?因为您的代码似乎想用[2=8;10, 3=9, 11=11]构建一个结果,但这不符合您给出的描述。 -
仅供参考: 1) 您应该翻转
filter和maps呼叫,因此您不必呼叫parseInt两次。 --- 2)divisors.stream()...逻辑是不必要的,因为最小的除数本质上是一个素数,所以你不必检查它。 -
提示: 要将
Set作为映射值,请使用groupingBy()而不是toMap,如Collectors.groupingBy(keyMapper, Collectors.toSet()) -
同意@Andreas,您似乎有向后映射。输入包含重复的数字是没有意义的(为什么两次产生相同的答案?)所以永远不应该有重复的键。您对问题的描述表明情况确实如此。
-
我可能混淆了映射表达式,所以是的,您的示例的等待结果将类似于 [2=[8,10],3=[9],11=[11]] .另外,谢谢你的建议!
标签: java dictionary stream set