2015-07-25 22 views
18

Tôi có đoạn mã sau và muốn thực hiện nó bằng các hàm lambda chỉ để giải trí. Nó có thể được thực hiện bằng cách sử dụng các phép toán tổng hợp cơ bản không?Làm thế nào để thực hiện lồng nhau 'if' báo cáo bằng cách sử dụng Java 8/lambda?

List<Integer> result = new ArrayList<>(); 

for (int i = 1; i <= 10; i++) { 
    if (10 % i == 0) { 
     result.add(i); 
     if (i != 5) { 
      result.add(10/i); 
     } 
    } 
} 

Sử dụng lambda:

List<Integer> result = IntStream.rangeClosed(1, 10) 
           .boxed() 
           .filter(i -> 10 % i == 0) 
           // a map or forEach function here? 
           // .map(return 10/i -> if i != 5) 
           .collect(Collectors.toList()); 

Trả lời

35

Các quan sát cần thiết ở đây là vấn đề của bạn liên quan đến một tổ chức phi đẳng cấu chuyển đổi : một yếu tố đầu vào duy nhất có thể lập bản đồ bằng không, một, hoặc hai yếu tố đầu ra. Bất cứ khi nào bạn nhận thấy điều này, bạn nên ngay lập tức bắt đầu tìm kiếm một giải pháp có liên quan đến flatMap thay vì map vì đó là cách duy nhất để đạt được chuyển đổi chung như vậy. Trong trường hợp cụ thể của bạn lần đầu tiên bạn có thể áp dụng filter cho một ánh xạ yếu tố one-to-zero, sau đó flatMap để lập bản đồ một-hai:

List<Integer> result = 
    IntStream.rangeClosed(1, 10) 
      .filter(i -> 10 % i == 0) 
      .flatMap(i -> i == 5 ? IntStream.of(i) : IntStream.of(i, 10/i)) 
      .boxed() 
      .collect(toList()); 
+1

Tôi thích cách bạn không chỉ trả lời câu hỏi mà còn dạy cách suy nghĩ về vấn đề để tìm ra giải pháp. – marcus

4

Bạn có thể khai báo một cơ thể cho một lambda. Ví dụ:

Runnable run =() -> System.out.println("Hey"); 

Có thể

Runnable run =() -> { 
    System.out.println("Hey"); 
}; 

Trong cơ thể, bạn có thể tạo báo cáo lồng nhau:

Runnable run =() -> { 
    int num = 5; 

    if(num == 5) { 
     System.out.println("Hey"); 
    } 
}; 
+0

nhưng có thể thực hiện với 'map',' filter', v.v. không? Tôi đang cố gắng tìm hiểu những điều cơ bản về hàm lambda. Cảm ơn. – LuckyGuess

+0

@ Z-1 Tôi không chắc chắn nếu các bộ lọc có thể làm điều này, nhưng cú pháp sẽ là '.filter (i -> {return yourLogic;})' – RAnders00

+0

@ Z-1 Một biểu thức lambda phát sinh từ việc sử dụng a * Giao diện chức năng * (một giao diện chỉ có 1 phương thức 'abstract', chẳng hạn như' Runnable'; có thể có nhiều phương thức 'default'). Ví dụ, một 'Thread' chấp nhận một' Runnable' trong hàm khởi tạo của nó. Chúng ta có thể viết 'Thread mới (() -> {});'. Bạn thậm chí có thể tạo các giao diện chức năng của riêng bạn. Vì vậy, để trả lời "* có thể làm điều đó với' map' và 'filter' *": ** yes **. Nó hoạt động cho * tất cả * lambdas. –

0

Hãy thử sử dụng flatMap:

List<Integer> result = IntStream.rangeClosed(1, 10) 
          .boxed() 
          .flatMap((i) -> { 
           List<Integer> results = new ArrayList<>(); 
           if (10 % i == 0) { 
            results.add(i); 
            if (i != 5) { 
             results.add(10/i); 
            } 
           } 
           return results.stream(); 
          }) 
          .collect(Collectors.toList()); 

Xem http://ideone.com/EOBiEP

1

Bạn có thể làm điều này:

 List<Integer> result1 = IntStream 
     .rangeClosed(1, 10) 
     .boxed() 
     .filter(i -> 10 % i == 0) 
     .map(i -> (i != 5 ? Stream.of(i, 10/i) : Stream.of(i))) 
     .flatMap(Function.identity()) 
     .collect(Collectors.toList()); 
3

Sử dụng flatMap như bạn đang cố gắng để thêm các yếu tố vào đường ống hoặc một Lập bản đồ 1 đến nhiều. Bản đồ là một ánh xạ một.

ArrayList<Integer> result = (ArrayList<Integer>) IntStream.rangeClosed(1, 10) 
       .boxed() 
       .filter(i -> 10 % i == 0) 
       .flatMap((Integer i) -> {return i!=5 ? Stream.of(i, (10/i)):Stream.of(i);}) 
       .collect(Collectors.toList()); 

Điều này dẫn đến cùng một danh sách như

ArrayList<Integer> result2 = new ArrayList<Integer>(); 

     for (int i = 1; i <= 10; i++) { 
      if (10 % i == 0) { 
       result2.add(i); 
       if (i != 5) { 
        result2.add(10/i); 
       } 
      } 
     } 

Trong trường hợp bạn tự hỏi đó là cách nhanh hơn các phương pháp lặp là nhanh hơn so với sử dụng các dòng ~ 3 lần.

Benchmark      Mode Cnt  Score  Error Units 
testStreams.Bench.loops  avgt 5  75.221 ± 0.576 ns/op 
testStreams.Bench.streams  avgt 5 257.713 ± 13.125 ns/op 
+1

Điều này thật thú vị. Cảm ơn điểm chuẩn. Tôi nhận thấy rằng quá, luồng là chậm hơn nhiều so với truyền thống cho vòng lặp. – LuckyGuess

+0

Tùy thuộc vào ứng dụng thực sự, các hoạt động trên int là một số các operartion đơn giản nhất bạn có thể làm, cho những gì bạn đang làm ở đây chi phí trong việc thiết lập luồng quá cao. Tôi tìm thấy câu trả lời thứ hai về [bài đăng này] (http://stackoverflow.com/questions/27925954/is-arrays-streamarray-name-sum-slower-than-iterative-approach/27994074#27994074) hữu ích. – Mantis

+0

chi phí trên luồng thực sự nhỏ hơn khi phạm vi vòng lặp tăng lên lớn hơn. không hoàn toàn biến mất trong trường hợp này mặc dù. – the8472

Các vấn đề liên quan