【问题标题】:Implement counting variable with lambda expression java用 lambda 表达式 java 实现计数变量
【发布时间】:2015-07-03 05:48:49
【问题描述】:

我有一个关于 lambda 表达式的问题。我有一个类 Pair,它应该包含一个 String 和一个 int。

Pair 从文件中获取字符串。 并且 int 代表行号。 到目前为止,我有这个:

 Stream<String> lineNumbers = Files.lines(Paths.get(fileName));
    List<Integer> posStream = Stream.iterate(0, x -> x + 1).limit(lineNumbers.count()).collect(Collectors.toList());
    lineNumbers.close();
    Stream<String> line = Files.lines(Paths.get(fileName));
    List<Pair> pairs = line.map((f) -> new Pair<>(f,1))
            .collect(Collectors.toList());
    pairs.forEach(f -> System.out.println(f.toString()));
    line.close();

我现在如何将文件编号输入到配对中? 是否有可以执行此操作的 lambda 表达式?还是我需要别的东西?

【问题讨论】:

    标签: java lambda java-8 java-stream


    【解决方案1】:

    有几种方法可以做到这一点。 Saloparenator's answer 建议的计数器技术可以如下实现,使用 AtomicInteger 作为可变计数器对象并假设明显的 Pair 类:

    List<Pair> getPairs1() throws IOException {
        AtomicInteger counter = new AtomicInteger(0);
        try (Stream<String> lines = Files.lines(Paths.get(FILENAME))) {
            return lines.parallel()
                        .map(line -> new Pair(line, counter.incrementAndGet()))
                        .collect(toList());
        }
    }
    

    问题是,如果流并行运行,计数器不会按照读取行的顺序递增!如果您的文件有几千行,就会发生这种情况。 Files.lines 流源将批处理成束的行并将它们分派给多个线程,然后这些线程将并行编号它们的批次,将它们的调用交错到incrementAndGet()。因此,这些行不会按顺序编号。如果您可以保证您的流永远不会并行运行,它将起作用,但编写可能按顺序返回不同结果的流通常是一个坏主意。

    这是另一种方法。由于无论如何您都将所有行读入内存,因此只需将它们全部读入列表即可。然后使用流对它们进行编号:

    static List<Pair> getPairs2() throws IOException {
        List<String> lines = Files.readAllLines(Paths.get(FILENAME));
        return IntStream.range(0, lines.size())
                        .parallel()
                        .mapToObj(i -> new Pair(lines.get(i), i+1))
                        .collect(toList());
    }
    

    【讨论】:

      【解决方案2】:

      另一种实用方法是使用整数生成器压缩流列表

      (我可以看到java8还没有它,但它本质上是将两个列表的每个单元格合并到一对列表中,所以很容易实现)

      你可以看到java8中的生成器示例here

      【讨论】:

        【解决方案3】:
        int cnt = 1;
        List<Pair> pairs = line.map((f) -> new Pair<>(f,cnt++))
                               .collect(Collectors.toList());
        

        我还没有尝试过,但可能有用。

        【讨论】:

        • 那行不通,因为 lambda 表达式需要一个 final 来执行它,所以我不能增加 lambda 表达式中的值
        • 那么我认为你不能使用 lambda 执行他想要的操作。无论如何 lambda 不应该以可变的方式使用。
        • 这是我作业中关于 lambda 表达式和流 xD 的一个小方法
        • 您可以构建一个计数器对象,每次获取都会增加值,将其声明为最终对象并在您的 lambda 中使用它。根据定义 lambda 是幂等的,这意味着如果您使用相同的参数多次调用它,它将每次返回相同的结果。这就是为什么我说在 lambda 中增加一个值是反函数的。
        • 使用最终 atomicInteger; .map(arr ->new Integer(i.getAndIncrement()))....
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-28
        • 2018-01-25
        • 1970-01-01
        • 2016-07-21
        • 2015-03-08
        • 2017-01-02
        相关资源
        最近更新 更多