2017-01-10 1 views
0

두 개의 목록이 있습니다. 하나는 어떤 게임에서 한 그룹의 각 개인에 대한 성공적인 시도 횟수를 보여줍니다.Java Streams와의 병렬 루핑?

public class SuccessfulAttempts{ 
    String name; 
    int successCount; 
} 

List<SuccessfulAttempts> success; 

각 개인의 총 시도 횟수.

public class TotalAttempts{ 
    String name; 
    int totalCount; 
} 

List<TotalAttempts> total; 

와 나는 그룹의 각 사람의 비율 성공을 보여주고 싶어요.

public class PercentageSuccess{ 
    String name; 
    float percentage; 
} 

List<PercentageSuccess> percentage; 

다음과 같이 처음 두 목록을 채우는 것으로 가정합니다.

success.add(new SuccessfulAttempts(Alice, 4)); 
success.add(new SuccessfulAttempts(Bob, 7)); 

total.add(new TotalAttempts(Alice, 5)); 
total.add(new TotalAttempts(Bob, 10)); 

이제 Java Streams를 사용하여 각 사람의 성공률을 계산하고 싶습니다. 그래서 실제로는 목록 List<PercentageSuccess> percentage에 대해 이런 종류의 결과가 필요합니다.

new PercentageSuccess(Alice, 80); 
new PercentageSuccess(Bob, 70); 

와 나는 (내가 루프를 사용하여 순차적으로 수행하는 방법을 알고) 병렬에서 그 (앨리스의 비율과 밥의 비율)을 계산하려고합니다. Java Streams (또는 다른 간단한 방법)로 어떻게 이것을 할 수 있습니까 ??

+0

앨리스의 비율은 5/5 = 80 %가 될 것인가? – Jerry06

+2

왜 첫 번째 장소에서 별도의 구조로 시도/성공을 유지하고 있습니까? –

+0

@ Jerry06. 편집 됨 :)) –

답변

4

귀하의 목록 중 하나를 쉽게지도에 액세스 할 수 있도록지도로 변환하는 것이 좋습니다. 다른 목록에서 반복해야하는 목록의 각 값은 O (n^2) 개의 복잡도가됩니다.

List<SuccessfulAttempts> success = new ArrayList<>(); 
List<TotalAttempts> total = new ArrayList<>(); 

success.add(new SuccessfulAttempts("Alice", 4)); 
success.add(new SuccessfulAttempts("Bob", 7)); 

total.add(new TotalAttempts("Alice", 5)); 
total.add(new TotalAttempts("Bob", 10)); 

// First create a Map 
Map<String, Integer> attemptsMap = success.parallelStream() 
    .collect(Collectors.toMap(SuccessfulAttempts::getName, SuccessfulAttempts::getSuccessCount)); 

// Loop through the list of players and calculate percentage. 
List<PercentageSuccess> percentage = 
    total.parallelStream() 
     // Remove players who have not participated from List 'total'. ('attempt' refers to single element in List 'total'). 
     .filter(attempt -> attemptsMap.containsKey(attempt.getName())) 
     // Calculate percentage and create the required object 
     .map(attempt -> new PercentageSuccess(attempt.getName(), 
        ((attemptsMap.get(attempt.getName()) * 100)/attempt.getTotalCount()))) 
     // Collect it back to list 
     .collect(Collectors.toList()); 

percentage.forEach(System.out::println); 
+0

답장을 보내 주셔서 감사합니다. Aetoros의 솔루션이 더 쉬운 솔루션이라는 것을 알았습니다. 안 그래? 너의 것와 함께 갈 어떤 이유라도있어? :)) –

+1

데이터가 정확히 같은 순서로 저장되고 미래에도 주문이 혼합되지 않는다면 Aetoros의 답변과 함께 갈 수 있습니다 :) 사실, 지도를 만드는 것보다 색인 기반으로 접근하는 것이 더 낫습니다. 또한, 반드시 totalAttempts의 모든 값에 대해 successfulAttempts 목록에 항목이 있는지 확인하십시오 (성공적으로 시도하지 않았다고 가정 할 때 적어도 0의 값이 저장됩니까?) 이러한 시나리오에서는 다시 색인과 함께 갈 수 없습니다 기반 접근법. –

+0

내 경우에는 명령이 문제가되지 않지만 후자 (0 값)가 될 수 있으며 명령도 발생할 수 있습니다. 나는 갱신을 볼 것이다. :)) –

1

배열의 배열이 동일하고 올바르게 정렬 된 경우 정수 인덱스를 사용하여 원본 목록 요소에 액세스 할 수 있습니다.

List<PercentageSuccess> result = IntStream.range(0, size).parallel().mapToObj(index -> /*get the elements and construct percentage progress for person with given index*/).collect(Collectors.toList()) 

이것은 당신이 주어진 SuccessAttempts 및 TotalAttempts에 대한 비율을 construncts PercentageSuccess하는 방법 또는 custructor를 만드는 것을 의미합니다.

IntStream.range(0, size).parallel() 

이 실제로 루프 평행 :

PercentageSuccess(SuccessfulAttempts success, TotalAttempts total) { 
    this.name = success.name; 
    this.percentage = (float) success.successCount/(float) total.totalCount; 
} 

는 그러면 평행 크기 0의 정수의 스트림을 구성. 그런 다음 각 정수를 index '번째 사람의 PercentageSuccess로 바꿉니다 (목록은 크기가 같고 섞이지 않아야하며 다른 코드는 올바르지 않은지 확인하십시오).
.mapToObj(index -> new PercentageSuccess(success.get(index), total.get(index)) 

최종적 또한

.collect(Collectors.toList()) 

으로 목록에 트림을 설정이 접근법 LinkedList의 인덱스에 의해 소자를 액세스 O (n)을 선정 다른리스트의 구현 사례 success 또는 total에서 최적 아니다 .

+0

) 블록 주석없이 코드의 작업 라인을 보여 주시겠습니까? :)) 그리고 더 많은 설명 pls를 추가하십시오. :)) –

+0

는 가장 간단한 해결책으로 보이며 테스트를 마친 후 업데이트됩니다. :)) –

+1

가장 단순하지만 제한이 있습니다 – Aeteros

1
private static List<PercentageAttempts> percentage(List<SuccessfulAttempts> success, List<TotalAttempts> total) { 

    Map<String, Integer> successMap = success.parallelStream() 
      .collect(Collectors.toMap(SuccessfulAttempts::getName, SuccessfulAttempts::getSuccessCount, (a, b) -> a + b)); 

    Map<String, Integer> totalMap = total.parallelStream() 
      .collect(Collectors.toMap(TotalAttempts::getName, TotalAttempts::getTotalCount)); 

    return successMap.entrySet().parallelStream().map(entry -> new PercentageAttempts(entry.getKey(), 
      entry.getValue() * 1.0f/totalMap.get(entry.getKey()) * 100)) 
      .collect(Collectors.toList()); 

} 
+0

답변 해 주셔서 감사합니다. Aetoros의 솔루션이 더 쉬운 솔루션이라는 것을 알았습니다. 안 그래? 너의 것와 함께 갈 어떤 이유라도있어? :)) –

+0

@SupunWijerathne은 입력 내용이 섞여 있지 않은 것에 대해 그의 코멘트를 볼 수 있습니다. 또한 * Alice, 4 *, Alice, 5 *와 같은 항목이 여러 개있을 경우 어떤 일이 발생합니까? 당신의 필요에 맞는 것이 무엇이든, 그것을 생각하지 마십시오. – Eugene

+0

실제로 제 경우에는 어쨌든 섞여 있지 않습니다. :)) 그래서 당신의 대답을 간단하게 만들까요? 만약 그렇다면 당신은 당신의 대답에 그것을 추가 할 수 있습니까? pls는 현재 하나를 삭제합니다. :)) –