2016-07-03 2 views
1

Моя проблема сводится к уменьшению List в связанном списке, но выводимые типы из функции уменьшения не кажутся правильными.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(); 
    } 
} 

Что я делаю неправильно?

EDIT После принятого ответа, мой код выглядит следующим образом:

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 не могу сказать, что третий аргумент функции сокращения не нужен, и он никогда не будет вызван, но это вопрос на другой день.

Второй Редактировать

Можно просто создать новый метод для уменьшения операций, как это потому, что третий аргумент для снижения может быть просто функция, которая ничего не делает.

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' более подходит для создания коллекции из потока. – Eran

+0

@Eran Мне не понравилось, что мне потребовалось реализовать 3 метода – michaelsnowden

+2

@michaelsnowden Попробуйте запустить «Стрим» параллельно, тогда вам понадобится объединитель. – 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 
    } 

Edit: Для того, чтобы сделать его работу с 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

Обратите внимание, что это не работает параллельно. Использование '.parallelStream()' in 'reverse' вместо' stream() 'приведет к неправильному результату. – Tunaki

+0

Спасибо, третий аргумент был совершенно неактуальен в этом сценарии. Для полноты я добавил метод, который заставляет его работать для 'parallelStream()'. Однако этот сценарий не очень подходит для параллельного потока. – CoronA

3

Проблема заключается в том, что сокращение предполагает возврат того же типа, который он накапливает. В этом случае null является Integer как a

Что вы можете сделать карту каждый Integer к Node, а затем уменьшить его узлы в связанном списке.

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

Этот ответ сработал в моем случае, но я не принял его, потому что я надеялся на апатриду. Я должен был указать это в вопросе. – michaelsnowden

+1

@michaelsnowden это безгражданная лямбда. Вы имеете в виду тот, который работает с неизменяемыми структурами данных? –

+1

Ой, да, вот что я имел в виду. – michaelsnowden

Смежные вопросы