Functional programming Java8:如何将下面的代码转换为函数?

Functional programming Java8:如何将下面的代码转换为函数?,functional-programming,java-8,Functional Programming,Java 8,如何在布尔数组上使用Java8的流API,而不是使用for循环?如何使用forEach、reduce等方法。? 我想去掉我用来维护状态的两个变量totalRelevant和retrieved。 在lambda表达式中,我们只能从词法上下文中引用final变量 import java.util.Arrays; import java.util.List; public class IRLab { public static void main(String[] args) {

如何在布尔数组上使用Java8的流API,而不是使用
for
循环?如何使用
forEach
reduce
等方法。? 我想去掉我用来维护状态的两个变量
totalRelevant
retrieved
。 在lambda表达式中,我们只能从词法上下文中引用
final
变量

import java.util.Arrays;
import java.util.List;

public class IRLab {

    public static void main(String[] args) {

        // predefined list of either document is relevant or not
        List<Boolean> documentRelivency = Arrays.asList(true, false, true, true, false);

        System.out.println("Precision\tRecall\tF-Measure");

        // variables for output
        double totalRelevant = 0.0;
        double retrieved = 0.0;

        for (int i = 0; i < documentRelivency.size(); ++i) {
            Boolean isRelevant = documentRelivency.get(i);

            // check if document is relevant
            if (isRelevant) totalRelevant += 1;

            // total number of retrieved documents will be equal to
            // number of document being processed currently, i.e. retrieved = i + 1
            retrieved += 1;

            // storing values using formulas
            double precision = totalRelevant / retrieved;
            double recall = totalRelevant / totalRelevant;
            double fmeasure = (2 * precision * recall) / (precision + recall);

            // Printing the final calculated values
            System.out.format("%9.2f\t%.2f\t%.2f\t\n", precision, recall, fmeasure);
        }
    }
}
导入java.util.array;
导入java.util.List;
公共级实验室{
公共静态void main(字符串[]args){
//文档的预定义列表是否相关
List documentRelivency=Arrays.asList(真、假、真、真、假);
System.out.println(“精度\tRecall\tF度量”);
//输出变量
双相关系数=0.0;
双检索=0.0;
对于(int i=0;i

如何使用Java8流API和Lambda表达式将上述代码转换为函数代码?我需要维护上述两个变量的状态。

不清楚为什么需要将代码更改为lambdas。目前它很短,lambdas不会使它变短或更干净。但是,如果确实需要,可以将共享状态封装在单独的对象中:

static class Stats {
    private int totalRelevant, retrieved;

    public void add(boolean relevant) {
        if(relevant)
            totalRelevant++;
        retrieved++;
    }

    public double getPrecision() {
        return ((double)totalRelevant) / retrieved;
    }

    public double getRecall() {
        return 1.0; // ??? was totalRelevant/totalRelevant in original code
    }

    public double getFMeasure() {
        double precision = getPrecision();
        double recall = getRecall();
        return (2 * precision * recall) / (precision + recall);
    }
}
并与lambda一起使用,如下所示:

Stats stats = new Stats();
documentRelivency.forEach(relevant -> {
    stats.add(relevant);
    System.out.format("%9.2f\t%.2f\t%.2f\t\n", stats.getPrecision(),
            stats.getRecall(), stats.getFMeasure());
});

Lambda在这里,但不是streamapi。似乎将流API用于此类问题并不是一个好主意,因为您需要输出可变容器的中间状态,这些状态应该严格按照给定的顺序进行变异。好的,如果您迫切需要流API,请将
.forEach
替换为
.Stream()。forEachOrdered

通常,只有在您设法摆脱导致一个元素的处理依赖于前一个元素的处理的可变状态时,将命令转换为函数代码才是一种改进

有一些变通方法可以让您合并可变状态,但您应该首先尝试找到一种不同的问题表示法,这种表示法可以在没有可变状态的情况下工作。在您的示例中,每个元素的处理取决于两个值,
totalRelevant
retrieved
。后者只是一个升序数,因此可以表示为一个范围,例如
IntStream.range(startValue,endValue)
。第二个源于布尔值列表,是子列表
(0,已检索)
(包含)中
true
值的数目

您可以在不需要之前的值的情况下重新计算该值,但在每个步骤中重复该列表可能代价高昂。因此,首先将列表收集到一个表示位集的
int
数字中,即
[true,false,true,true,false]
变为
0b_10110
。然后,您可以使用内部操作获得一位的数量:

List<Boolean> documentRelivency = Arrays.asList(true, false, true, true, false);
int numBits=documentRelivency.size(), bitset=IntStream.range(0, numBits)
    .map(i -> documentRelivency.get(i)? 1<<(numBits-i-1): 0).reduce(0, (i,j) -> i|j);
System.out.println("Precision\tRecall\tF-Measure");
IntStream.rangeClosed(1, numBits)
         .mapToObj(retrieved -> {
             double totalRelevant = Integer.bitCount(bitset&(-1<<(numBits-retrieved)));
             return String.format("%9.2f\t%.2f\t%.2f",
                totalRelevant/retrieved, 1f, 2/(1+retrieved/totalRelevant));
         })
         .forEach(System.out::println);
List documentRelivency=Arrays.asList(真、假、真、真、假);
int numBits=documentRelivency.size(),位集=IntStream.range(0,numBits)
.map(i->documentRelivency.get(i)?1{

double TotalRelative=整数。位计数(位集&(-1先陈述你想要做什么和拥有什么。这会更容易帮助。@Tunaki编辑。请看一看。我看不到任何关于你想要什么的解释。它仍然不清楚。举个例子:
recall=totalRelevant/totalRelevant;
很明显,
recall
总是一个。那么这有什么意义呢语句?放在lambda表达式中看起来没有什么意义。@Holger这不是生产代码。我只是在使用公式。主要问题是将代码转换为函数式。使用函数式编程风格不是让代码更可读、更易维护吗?那么,我们不应该一直使用它吗?@MajeedSiddiqui Do你真的觉得上面的代码比for循环更可读吗?这只是一种不同的编写代码的方法,可能适合也可能不适合某些任务。@MajeedSiddiqui,没有我们应该经常使用的编程概念。就像你不能用锤子修复所有东西一样。你应该使用最合适的工具来解决每个问题m、
fmeasure=2/(1+retrieved/totalrelated)
…@Majeed Siddiqui:当然,你可以混合使用函数式编程和命令式编程。你甚至可以混合使用面向对象编程…