2016-07-03 10 views
1

Mein Problem läuft im Grunde darauf hinaus, eine List in eine verkettete Liste zu reduzieren, aber die abgeleiteten Typen von der Reduce-Funktion scheinen nicht richtig zu sein.Java 8 Liste auf Linkedlist reduzieren

Meine Liste wie diese

[0, 1, 2] 

aussehen werde ich die Funktion reduzieren erwarten, dass dies bei jedem tun reduzieren Schritt

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 

jedoch die Verringerung Funktion scheint zu denken, dass dies nicht funktionieren wird weil ich denke, dass es nicht die Identität eines Node ist.

Hier ist mein Code.

Was mache ich falsch?

EDIT Nach der akzeptierten Antwort, sieht mein Code wie folgt aus:

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

Und es druckt jetzt

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

Ich weiß immer noch nicht, warum Java kann nicht sagen, dass Das dritte Argument der Reduce-Funktion ist unnötig und wird niemals aufgerufen, aber das ist eine Frage für einen anderen Tag.

Zweite bearbeiten

Es ist möglich, nur eine neue Methode erstellen für Operationen wie diese zu reduzieren, da das dritte Argument nur zu reduzieren, kann eine Funktion sein, die nichts tut.

+1

Warum nicht ' sammeln statt "reduzieren"? 'collect' ist besser geeignet, um eine Sammlung aus einem Stream zu erstellen. – Eran

+0

@Eran Ich mochte es nicht, dass es mich erfordert, 3 Methoden zu implementieren – michaelsnowden

+2

@michaelsnowden Versuchen Sie, den 'Stream' parallel zu laufen, dann brauchen Sie den Combiner. – Flown

Antwort

4

Sie die anderen Betreiber reduzieren können,

tun
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 
    } 

Edit: Um es mit parallelStream funktioniert:

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

Beachten Sie, dass dies nicht parallel funktioniert. Die Verwendung von '.parallelStream()' in 'reverse' anstelle von' stream() 'führt zu einem falschen Ergebnis. – Tunaki

+0

Danke, das dritte Argument war in diesem Szenario völlig irrelevant. Der Vollständigkeit halber habe ich eine Methode hinzugefügt, die es für 'parallelStream()' funktioniert. Dieses Szenario ist jedoch für den parallelen Strom nicht sehr geeignet. – CoronA

3

Das Problem, das Sie haben, ist, dass reduzieren, ist die Rückkehr der gleichen Art, die es ansammelt. In diesem Fall ist null ein Integer wie a

Was können Sie tun Karte ist jedes Integer einen Node und dann die Knoten in einer verknüpften Liste reduzieren.

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

druckt

2 
1 
0 
+0

Diese Antwort funktionierte in meinem Fall, aber ich akzeptierte es nicht, weil ich auf ein staatenloses Lambda gehofft hatte. Ich hätte das in der Frage angeben sollen. – michaelsnowden

+1

@michaelsnowden das ist ein staatenloses Lambda. Meinst du eine, die auf unveränderlichen Datenstrukturen operiert? –

+1

Whoops, ja das ist was ich meinte. – michaelsnowden