Java 8将列表缩减为链表

mic*_*den 2 java reduce linked-list java-8

我的问题基本上归结为将a减少List到链表,但是reduce函数的推断类型似乎不对.

我的清单看起来像这样

[0, 1, 2]
Run Code Online (Sandbox Code Playgroud)

我希望reduce函数在每个reduce步骤中执行此操作

null                            // identity (a Node)
Node(0, null)                   // Node a = null, int b = 0
Node(1, Node(0, null))          // Node a = Node(0, null), int b = 1
Node(2, Node(1, Node(0, null))) // Node a = Node(1, Node(0, null)), int b = 2
Run Code Online (Sandbox Code Playgroud)

但是,reduce函数似乎认为这不起作用,因为我猜它不认为标识是一个节点.

这是我的代码.

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Example {
    static class Node {
        int value;
        Node next;

        public Node(int value, Node next) {
            this.value = value;
            this.next = next;
        }
    }

    static Node reverse(List<Integer> list) {
        return list.stream()
                .reduce(null, (a, b) -> new Node(b, a)); // error: thinks a is an integer
    }

    void run() {
        List<Integer> list = IntStream.range(0, 3)
                .boxed()
                .collect(Collectors.toList());
        Node reversed = reverse(list);
    }

    public static void main(String[] args) {
        new Example().run();
    }
}
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?

编辑 在接受的答案后,我的代码如下所示:

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Example {
    static class Node {
        int value;
        Node next;

        public Node(int value, Node next) {
            this.value = value;
            this.next = next;
        }

        @Override
        public String toString() {
            return "Node{" +
                    "value=" + value +
                    ", next=" + next +
                    '}';
        }
    }

    static Node reverse(List<Integer> list) {
        return list.stream()
                .reduce(null, (n, i) -> {
                    System.out.println("Will happen"); // to demonstrate that this is called
                    return new Node(i, n);
                }, (n1, n2) -> {
                    System.out.println("Won't happen"); // and this never is
                    return new Node(n1.value, n2);
                });
    }

    void run() {
        List<Integer> list = IntStream.range(0, 3)
                .boxed()
                .collect(Collectors.toList());
        Node reversed = reverse(list);
        System.out.println(reversed);
    }

    public static void main(String[] args) {
        new Example().run();
    }
}
Run Code Online (Sandbox Code Playgroud)

它现在打印

Will happen
Will happen
Will happen
Node{value=2, next=Node{value=1, next=Node{value=0, next=null}}}
Run Code Online (Sandbox Code Playgroud)

我仍然不知道为什么Java不能告诉reduce函数的第三个参数是不必要的,它永远不会被调用,但这是另一天的问题.

第二次编辑

可以只为这样的减少操作创建一个新方法,因为reduce的第三个参数可以只是一个什么都不做的函数.

static <T, U> U reduce(Stream<T> stream, U identity, BiFunction<U, ? super T, U> accumulator) {
    return stream.reduce(identity, accumulator, (a, b) -> null);
}

static Node reverse(List<Integer> list) {
    return reduce(list.stream(), null, (n, i) -> new Node(i, n));
}
Run Code Online (Sandbox Code Playgroud)

Cor*_*onA 5

你可以使用另一个reduce运算符

    static Node reverse(List<Integer> list) {
      return list.stream()
        .reduce(
          (Node) null, //the empty element
          (n, i) -> new Node(i, n) , //combining a Node and an Integer
          (n1, n2) -> new Node(n1.value, n2)); // could be anything
    }
Run Code Online (Sandbox Code Playgroud)

编辑:使其适用于parallelStream:

    public static Node merge(Node n1, Node n2) {
        if (n1 == null) {
            return n2;
        } else {
            return new Node(n1.value, merge(n1.next, n2));
        }
    }

    static Node reverse(List<Integer> list) {
      return list.stream()
        .reduce(
          (Node) null, //the empty element
          (n, i) -> new Node(i, n) , //combining a Node and an Integer
          (n1, n2) -> merge(n1, n2)); // combining two Nodes
    }
Run Code Online (Sandbox Code Playgroud)

  • 请注意,这不是并行工作.在`reverse`中使用`.parallelStream()`而不是`stream()`会导致错误的结果. (2认同)