2016-08-11 5 views
1

저는 Coursera에서 프로그램을 구현하려고했습니다. 프로그램 문은 다음과 같습니다.Whys 스트림이 너무 빠름

음수가 아닌 정수 a0, ..., an-1의 시퀀스가 ​​주어지면 최대 pairwise 곱, 즉 시퀀스의 두 개의 다른 요소를 곱하여 얻을 수있는 최대 정수를 찾습니다.

저는 솔루션을 구현하고 어떤 것이 가장 잘 작동 하는지를 확인하기 위해 다양한 방법을 시도하고있었습니다.

스트림이 여전히 빠릅니다.

왜 그렇게됩니까?

필자는 인상적이었습니다. 정렬하지 않고 가장 큰 두 요소를 찾고이를 곱하는 것이 가장 좋습니다. 스트림 정렬 (순차 스트림이 병렬 스트림보다 빠름)이이 방법보다 더 나은 결과를 제공합니까?

내 프로그램

import java.util.ArrayList; 
    import java.util.Comparator; 
    import java.util.List; 
    import java.util.Random; 
    import java.util.stream.Collectors; 

    public class MaxProduct { 
     public static void main(String[] args) { 
      List<Long> testList = createRandomArrayOfSize(30000000); 

      warmup(testList); 
      System.out.println("Warmup done"); 

      Measure.meaureTime("No sorting, finding largest 2 elements and multiplying", 
        () -> findMaxProductByFindingLargest2Elements(new ArrayList<>(testList))); 
      Measure.meaureTime("Sorting, Multiplying last 2 elements", 
        () -> findMaxProductUsingSorting(new ArrayList<>(testList))); 
      Measure.meaureTime("Sorting using streams, Multiplying last 2 elements", 
        () -> findMaxProductUsingStreamSorting(new ArrayList<>(testList))); 
      Measure.meaureTime("Parallel sorting using streams, Multiplying last 2 elements by reduction", 
        () -> findMaxProductReducingParallelStream(new ArrayList<>(testList))); 
     } 

     public static long findMaxProductByFindingLargest2Elements(List<Long> list) { 
      long largest = 0; 
      long secondlargest = 0; 
      for (Long no : list) { 
       if (no > largest) { 
        secondlargest = largest; 
        largest = no; 
       } 
      } 
      return largest * secondlargest; 
     } 

     public static long findMaxProductUsingSorting(List<Long> list) { 
      list.sort(Comparator.naturalOrder()); 
      return list.get(list.size() - 1) * list.get(list.size() - 2); 
     } 

     public static long findMaxProductUsingStreamSorting(List<Long> list) { 
      List<Long> collect = list.stream().sorted(Comparator.naturalOrder()).collect(Collectors.toList()); 
      return collect.get(list.size() - 1) * collect.get(list.size() - 2); 
     } 

     public static long findMaxProductReducingParallelStream(List<Long> list) { 
      return list.parallelStream().sorted(Comparator.reverseOrder()).limit(2).reduce((x, y) -> x * y).get(); 
     } 

     private static class Measure { 
      private static final int NO_OF_ITERATIONS = 3; 

      private static void meaureTime(String description, Runnable runnable) { 
       long startTime = System.nanoTime(); 
       for (int i = 0; i < NO_OF_ITERATIONS; i++) { 
        runnable.run(); 
       } 
       long timeTakenInNanos = System.nanoTime() - startTime; 
       System.out.println(description + " : " + (timeTakenInNanos/3)); 
      } 
     } 

     private static void warmup(List<Long> testList) { 
      findMaxProductByFindingLargest2Elements(new ArrayList<>(testList)); 
      findMaxProductUsingSorting(new ArrayList<>(testList)); 
      findMaxProductUsingStreamSorting(new ArrayList<>(testList)); 
      findMaxProductReducingParallelStream(new ArrayList<>(testList)); 
     } 

     private static List<Long> createRandomArrayOfSize(int size) { 
      return new Random().longs(size, 1, 10000000).boxed().collect(Collectors.toList()); 
     } 
    } 

업데이트 결과

없음 정렬, 최대 2 개 요소를 발견하고 곱 : 778547847
정렬을, 마지막 두 요소를 곱 : 13423659115 개
정렬 사용하여 스트림을, 마지막 두 요소에 곱하기 : 15518997158
str을 사용한 병렬 정렬 EAMS, 감소 지난 2 개 요소를 곱 : 5405983848

는 첫 번째 방법에서 문제가 코드

에게 업데이트되었습니다. 가장 큰 no가 0 번째 인덱스에 있다면, product는 0이 될 것입니다. 그것을 고칠 필요가 있습니다.

스트림은
내 테스트 코드의 실수 빠른 아니다. 실수를 수정했습니다. 그리고 지금 예상대로 일합니다.

+0

어떤 코스? –

+0

https://www.coursera.org/learn/algorithmic-toolbox –

+1

아직 몇 가지 문제가 있습니다. 1) 'warmup'을 호출 한 후리스트가 정렬됩니다. 2) 비교하는 함수가 동일한 결과를 제공하지 않습니다. 3) 마이크로 벤치 마크 작성 방법은 http://stackoverflow.com/q/504103/2568885를 참조하십시오. – binoternary

답변

0

테스트에 결함이 있습니다. 스트림을 실행하는 시간에 목록이 이미 정렬되어 있으므로 그만큼 빠릅니다.

+0

감사합니다. 문제를 해결하고 다시 시도하십시오. –

+0

@PaulNibin 고정되어 있지 않습니다. 당신의'measureTime'은 여러 반복을하고 그 사이의리스트는 리셋되지 않습니다. – davmac

+0

초기 질문은 "왜 그런가요?"였습니다. 그리고 그의 대답은 (그의 질문을 바꾸기 전에) 그의 질문에 대한 대답을 제공했다. – macsniper

2

불행히도 스트림이 반드시 빠르지는 않습니다.

findMaxProductUsingStreamSorting은 스트림을 지정하지만 collect 또는 findFirst으로는 스트림을 지정하지 않습니다. 그것은 목록을 변경하지 않습니다. 따라서 두 목록 가져 오기의 제품 만 수행됩니다. 결과도 잘못 될 것입니다.

스트림을 사용하면 반복이 늦게 처리되므로 정렬, 필터링 등이 영리하게 실행될 수 있습니다.

+0

감사합니다. 실수도 수정했습니다. 이제 스트림이 더 이상 빠르지 않습니다. 코드 검토 기술을 습득해야합니다. –

관련 문제