2016-07-03 31 views
1

我的問題基本上歸結爲將List減少到鏈接列表,但從reduce函數推斷的類型似乎不正確。Java 8減少列表到鏈接列表

我的名單看起來是這樣

[0, 1, 2] 

我預計減少功能在每次做這個簡步驟

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 

然而,減少功能似乎認爲這是行不通的因爲我猜想它不認爲身份是一個節點。

這是我的代碼。

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(); 
    } 
} 

我在做什麼錯?

編輯 接受的答案後,我的代碼看起來是這樣的:

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(); 
    } 
} 

而且它現在打印

Will happen 
Will happen 
Will happen 
Node{value=2, next=Node{value=1, next=Node{value=0, next=null}}} 

我仍然不知道爲什麼的Java不能告訴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)); 
} 
+1

爲什麼不使用'收集'而不是'減少'? 'collect'更適合從Stream創建Collection。 – Eran

+0

@Eran我不喜歡它需要我實現3種方法 – michaelsnowden

+2

@michaelsnowden嘗試並行運行'Stream',然後您需要組合器。 – Flown

回答

4

您可以用其他的減少運營商,做

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 
    } 

編輯:使其與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 
    } 
+2

請注意,這不能並行工作。在reverse中使用'.parallelStream()'而不是'stream()'會導致錯誤的結果。 – Tunaki

+0

謝謝,第三個參數在這種情況下完全不相關。爲了完整性,我添加了一個方法,使其適用於'parallelStream()'。然而,這種情況並不適合並行流。 – CoronA

3

您遇到的問題是減少期望返回它積累的相同類型。在這種情況下nullIntegera

你可以做的是地圖中的每個IntegerNode,然後降低到節點鏈表。

static Node reverse(List<Integer> list) { 
    return list.stream() 
      .map(i -> new Node(i, null)) 
      .reduce(null, (a, b) -> { 
       b.next = a; 
       return b; 
      }); 
} 

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

打印

2 
1 
0 
+0

這個答案適用於我的情況,但我不接受它,因爲我希望得到一個無狀態lambda。我應該在問題中指出這一點。 – michaelsnowden

+1

@michaelsnowden這是一個無國籍的lambda。你的意思是在不可變的數據結構上運行嗎? –

+1

哎呀,是的,這就是我的意思。 – michaelsnowden