Java 如何将搜索友好号码的实现从命令式转变为功能性?
我有一个搜索友好数字算法的简单命令式实现。现在我试着让它更实用Java 如何将搜索友好号码的实现从命令式转变为功能性?,java,functional-programming,Java,Functional Programming,我有一个搜索友好数字算法的简单命令式实现。现在我试着让它更实用 public static void search(){ for(int i = 1; i < 10000; i++){ for(int j = i+1; j < 10000; j++){ if(isAmicable(i, j)){ System.out.println(i + " " + j); }
public static void search(){
for(int i = 1; i < 10000; i++){
for(int j = i+1; j < 10000; j++){
if(isAmicable(i, j)){
System.out.println(i + " " + j);
}
}
}
}
public static boolean isAmicable(int i, int j){
return sumProperDivisors(i) == j && sumProperDivisors(j) == i;
}
public static int sumProperDivisors(int num){
int result = 0;
for(int i = 1; i < num; i++){
if(num%i == 0) result +=i;
}
return result;
}
我看不到任何状态或副作用可以减少。
在这个实现中还应该做些什么来满足FP范式?如果(isAmicable(p,o))和使用
System.out.println(p+“”+o)进行forEach之后,使用filter代码>或带有形成消息和afrerSystem.out.println的map
这里有一个替代方案,可以生成所有友好对的map
,而不是产生副作用:
Map<Integer,Integer> pairs =
IntStream.range(1, 10000)
.boxed()
.flatMap(p -> IntStream.range(p+1, 10000)
.filter(o -> isAmicable(p, o))
.mapToObj(o -> new SimpleEntry<>(p,o)))
.collect(Collectors.toMap(Map.Entry::getKey,Map.Entry::getValue));
映射对=
IntStream.range(11000)
.boxed()
.flatMap(p->IntStream.range(p+11000)
.filter(o->isAmicable(p,o))
.mapToObj(o->newsimplentry(p,o)))
.collect(Collectors.toMap(Map.Entry::getKey,Map.Entry::getValue));
当然,就性能而言,这是相当糟糕的,因为您对同一个i
计算了多次sumpropertivisiors(i)
。为每个i
计算一次sumpropertivisiors(i)
,将结果存储在Map
中,并检查哪些i
和j
对满足sumpropertivisiors(i)==j和&sumpropertivisiors(j)==i
,这是个好主意,但随后声明一个新变量。这个映射对可以被另一个纯函数替换吗?@pobu它是一个纯函数,有一个返回值。你必须以某种方式归还友好的一对。你会用什么来代替地图?如果将search()
的返回类型从void更改为Map
,则可以消除该变量。然后,您只需返回流管道的结果。解决方案中有一个自动装箱(int->Integer),它可以真正提高性能bad@pobu您是运行了基准测试,还是只是假设性能会很差?我用System.currentTimeMillis()做了一个非常简单的基准测试。以下是结果:search()-6002秒;流();和对()-9918秒。我应该重复几次来验证结果。
Map<Integer,Integer> pairs =
IntStream.range(1, 10000)
.boxed()
.flatMap(p -> IntStream.range(p+1, 10000)
.filter(o -> isAmicable(p, o))
.mapToObj(o -> new SimpleEntry<>(p,o)))
.collect(Collectors.toMap(Map.Entry::getKey,Map.Entry::getValue));