使用 map().reduce() 初始化链表节点
Initialize a Linked List nodes using map().reduce()
我想使用 java 流对节点 class 进行初始化。我如何使用地图和减少流操作来执行此操作?
Node node5 = new Node(5,null);
Node node4 = new Node(4,node5);
Node node3 = new Node(3,node4);
Node node2 = new Node(2,node3);
Node node1 = new Node(1,node2);
我试过类似的方法,但无法编译
Node node = Arrays.stream(new int[]{1,2,3,4,5})
.map((i, n) -> new Node(i, n)
.reduce(null, new SingleList.Node(i, n)));
我想将数组中的每个元素映射到 Node(int i , Node n)
,然后将其缩减为 Node
。我在这里错过了什么?
您可以使用 Stream API 和特别是 reduce()
操作生成链表。
但请记住,从本质上讲,这是模仿 for
循环的一种棘手方法(这将是一个更合适的选择),并且此流不能并行执行。
为了创建包含所需数量元素的流,无需生成数组然后将其用作 stream-source。相反,我们可以使用 IntStream.range()
, which expects start and end int
values (it will work only if start < end
) or IntStream.iterate()
.
创建一个流
注意 需要 box()
操作才能将 IntStream
转换为对象流为了访问这种类型的 reduce(identity, accumulator, combiner)
,它允许提供与流中元素类型不同的类型标识。
这种形式的 reduce()
不适用于 IntStream
。
尾节点应作为reduce()
操作的身份提供。 accumulator函数负责以相反的顺序(from tail to head)生成链表。作为流管道执行结果返回的节点将是头节点。
Combiner 函数,用于组合并行生成的部分结果,抛出一个 AssertionError
因为如果我们允许并行执行,每个线程将实例化自己的身份(尾节点),这意味着节点链接不正确。
int tailValue = 5;
int headValue = 1;
// generating the linked list
Node head = IntStream.range(headValue, tailValue)
.boxed()
.reduce(new Node(tailValue, null),
(Node node, Integer value) -> new Node(node.getValue() - 1, node),
(Node left, Node right) -> {throw new AssertionError("should not be used in parallel");});
// printing the linked list
Node cur = head;
while (cur != null) {
System.out.println(cur);
cur = cur.getNext();
}
输出:
Node { value = 1 }
Node { value = 2 }
Node { value = 3 }
Node { value = 4 }
Node { value = 5 }
Tried something like this, which does not compile
Node node = Arrays.stream(new int[]{1,2,3,4,5})
.map((i, n) -> new Node(i, n))
.reduce(null, new SingleList.Node(i, n)));
Arrays.stream(new int[]{1,2,3,4,5})
将生成 IntStream
(不是 Stream
)。
操作 map()
,应用于 IntStream
,需要一个类型为 IntUnaryOperator
的参数,它是一个接受类型为 int
和 returns int
还有
为了将基元流转换为对象流,您应该使用 mapToObj()
,它需要一个 IntFunction
(一个接受单个 int
参数和returns 一个对象)。
可用于 IntStream
的 reduce(int identity, IntBinaryOperator combiner)
形式需要基本类型 int
的 身份 及其 combiner 是 IntBinaryOperator
类型,即它需要 int
并产生 int
。因此,它不会编译。
您的解决方案中还有一个逻辑缺陷 - 您试图为每个蒸汽元素创建一个 节点 两次:第一次在 map()
内,然后在期间reduce()
操作,这显然是多余的。
根据文档 map()
是一个 stateless operation 它不应该“意识到”之前遇到的元素。这意味着它对生成 节点 没有帮助,因为它无法提供对 下一个节点 .
的引用
上面使用的虚拟 Node
class:
public static class Node {
private int value;
private Node next;
public Node(int value, Node next) {
this.value = value;
this.next = next;
}
public int getValue() {
return value;
}
public Node getNext() {
return next;
}
@Override
public String toString() {
return "Node {" +
" value = " + value + " }";
}
}
恕我直言,不需要流。只需创建一个所需长度的数组,使用 Arrays.setAll 方法填充数组并获取最后一个元素:
Node[] nodes = new Node[5];
Arrays.setAll(nodes, i -> new Node(nodes.length - i , i == 0 ? null : nodes[i-1]));
Node node = nodes[nodes.length-1];
如果你想用数组的特定值而不是从 0 到 n 来初始化对象 Node
的 List
,你可以使用 iterate
操作来生成索引并从最后一个元素到第一个元素遍历数组。然后,正如您所建议的,您可以将每个 int
映射到 Integer
(或使用 boxed
操作),然后使用 reduce
操作从底部。
int[] vet = new int[]{7, 15, 6, 32, 44};
Node node = IntStream.iterate(vet.length - 1, i -> i >= 0, i -> i - 1)
.mapToObj(i -> i)
.reduce(null, (n, i) -> new Node(vet[i], n), (n1, n2) -> {
throw new RuntimeException("No parallel execution supported");
});
前面的代码引用了一个 Node
实现,如下所示:
class Node {
private int info;
private Node next;
public Node(int info, Node next) {
this.info = info;
this.next = next;
}
//... getters & setters ...
}
输出
Node temp = node;
while (temp != null) {
System.out.println(temp.getInfo());
temp = temp.next;
}
我想使用 java 流对节点 class 进行初始化。我如何使用地图和减少流操作来执行此操作?
Node node5 = new Node(5,null);
Node node4 = new Node(4,node5);
Node node3 = new Node(3,node4);
Node node2 = new Node(2,node3);
Node node1 = new Node(1,node2);
我试过类似的方法,但无法编译
Node node = Arrays.stream(new int[]{1,2,3,4,5})
.map((i, n) -> new Node(i, n)
.reduce(null, new SingleList.Node(i, n)));
我想将数组中的每个元素映射到 Node(int i , Node n)
,然后将其缩减为 Node
。我在这里错过了什么?
您可以使用 Stream API 和特别是 reduce()
操作生成链表。
但请记住,从本质上讲,这是模仿 for
循环的一种棘手方法(这将是一个更合适的选择),并且此流不能并行执行。
为了创建包含所需数量元素的流,无需生成数组然后将其用作 stream-source。相反,我们可以使用 IntStream.range()
, which expects start and end int
values (it will work only if start < end
) or IntStream.iterate()
.
注意 需要 box()
操作才能将 IntStream
转换为对象流为了访问这种类型的 reduce(identity, accumulator, combiner)
,它允许提供与流中元素类型不同的类型标识。
这种形式的 reduce()
不适用于 IntStream
。
尾节点应作为reduce()
操作的身份提供。 accumulator函数负责以相反的顺序(from tail to head)生成链表。作为流管道执行结果返回的节点将是头节点。
Combiner 函数,用于组合并行生成的部分结果,抛出一个 AssertionError
因为如果我们允许并行执行,每个线程将实例化自己的身份(尾节点),这意味着节点链接不正确。
int tailValue = 5;
int headValue = 1;
// generating the linked list
Node head = IntStream.range(headValue, tailValue)
.boxed()
.reduce(new Node(tailValue, null),
(Node node, Integer value) -> new Node(node.getValue() - 1, node),
(Node left, Node right) -> {throw new AssertionError("should not be used in parallel");});
// printing the linked list
Node cur = head;
while (cur != null) {
System.out.println(cur);
cur = cur.getNext();
}
输出:
Node { value = 1 }
Node { value = 2 }
Node { value = 3 }
Node { value = 4 }
Node { value = 5 }
Tried something like this, which does not compile
Node node = Arrays.stream(new int[]{1,2,3,4,5})
.map((i, n) -> new Node(i, n))
.reduce(null, new SingleList.Node(i, n)));
Arrays.stream(new int[]{1,2,3,4,5})
将生成 IntStream
(不是 Stream
)。
操作 map()
,应用于 IntStream
,需要一个类型为 IntUnaryOperator
的参数,它是一个接受类型为 int
和 returns int
还有
为了将基元流转换为对象流,您应该使用 mapToObj()
,它需要一个 IntFunction
(一个接受单个 int
参数和returns 一个对象)。
可用于 IntStream
的 reduce(int identity, IntBinaryOperator combiner)
形式需要基本类型 int
的 身份 及其 combiner 是 IntBinaryOperator
类型,即它需要 int
并产生 int
。因此,它不会编译。
您的解决方案中还有一个逻辑缺陷 - 您试图为每个蒸汽元素创建一个 节点 两次:第一次在 map()
内,然后在期间reduce()
操作,这显然是多余的。
根据文档 map()
是一个 stateless operation 它不应该“意识到”之前遇到的元素。这意味着它对生成 节点 没有帮助,因为它无法提供对 下一个节点 .
上面使用的虚拟 Node
class:
public static class Node {
private int value;
private Node next;
public Node(int value, Node next) {
this.value = value;
this.next = next;
}
public int getValue() {
return value;
}
public Node getNext() {
return next;
}
@Override
public String toString() {
return "Node {" +
" value = " + value + " }";
}
}
恕我直言,不需要流。只需创建一个所需长度的数组,使用 Arrays.setAll 方法填充数组并获取最后一个元素:
Node[] nodes = new Node[5];
Arrays.setAll(nodes, i -> new Node(nodes.length - i , i == 0 ? null : nodes[i-1]));
Node node = nodes[nodes.length-1];
如果你想用数组的特定值而不是从 0 到 n 来初始化对象 Node
的 List
,你可以使用 iterate
操作来生成索引并从最后一个元素到第一个元素遍历数组。然后,正如您所建议的,您可以将每个 int
映射到 Integer
(或使用 boxed
操作),然后使用 reduce
操作从底部。
int[] vet = new int[]{7, 15, 6, 32, 44};
Node node = IntStream.iterate(vet.length - 1, i -> i >= 0, i -> i - 1)
.mapToObj(i -> i)
.reduce(null, (n, i) -> new Node(vet[i], n), (n1, n2) -> {
throw new RuntimeException("No parallel execution supported");
});
前面的代码引用了一个 Node
实现,如下所示:
class Node {
private int info;
private Node next;
public Node(int info, Node next) {
this.info = info;
this.next = next;
}
//... getters & setters ...
}
输出
Node temp = node;
while (temp != null) {
System.out.println(temp.getInfo());
temp = temp.next;
}