2017-01-10 16 views
0

私は2つのリストを持っています。 1つは、いくつかのゲームのためのグループの人々の各個人の成功した試みの数を示しています。Javaストリームによる並列ルーピング?

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; 

このような最初の2つのリストを作成したとします。

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ストリーム(または他の簡単な方法)でこれを達成することができますか?

+0

アリスの割合は、4月5日= 80%でなければなりませんか? – Jerry06

+2

なぜあなたは最初の場所で別々の構造で試行錯誤を続けていますか? –

+0

@ Jerry06が正しい。編集:) :) –

答えて

4

あなたのリストの1つをマップに変換して、より簡単にアクセスできるようにすることをお勧めします。そうでなければ、O(n^2)の複雑さになるもう一方のリストでループしなければならない1つのリストの各値について。

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の解決策を見つけました。ではない? Aetorosのものではなく、あなたのものと一緒に行く理由は何ですか? :)) –

+1

あなたのデータが正確に同じ順序で保存され、今後も注文が混ざらないなら、あなたは間違いなくAetorosの答えに行くことができます:)実際問題として、マップを作成するよりも、インデックスとしてのアプローチが優れています。また、totalAttemptsのすべての値について、successfulAttemptsリストのエントリが確実に存在することを確認してください(成功した試行は行われませんでしたが、少なくとも0の値が保存されるでしょうか?)これらのシナリオでは、ベースのアプローチ。 –

+0

私の場合、注文は問題ではありませんが、後者(0値)は問題の可能性があり、注文も発生する可能性があります。私は更新を見てみましょう。 :)) –

1

配列が同じでsizeであり、正しく並べられている場合は、整数インデックスを使用して元のリスト要素にアクセスできます。

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を作成しなければならないことを意味します。

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

次に、あなたが平行であるサイズに0からの整数の流れを構築:

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

これは実際にループの並列です。次に、各整数をindex '番目の人のPercentageSuccessにします(リストは同じサイズでシャッフルされていないことを保証する必要がありますが、私のコードは正しくありません)。

.mapToObj(index -> new PercentageSuccess(success.get(index), total.get(index)) 

、最終的に

.collect(Collectors.toList()) 

でリストにストリームを回すまた、このアプローチは、場合success又はtotalに最適ではないインデックスで要素にアクセスするためのO(n)のコストでのLinkedListまたは他のリストの実装であります。

+0

あなたのブロックコメントなしでコードの作業ラインを表示できますか?:))さらにいくつかの説明を追加してください。 :)) –

+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の解決策を見つけました。ではない? Aetorosのものではなく、あなたのものと一緒に行く理由は何ですか? :)) –

+0

@SupunWijerathne入力がシャッフルされていないことについての彼のコメントを参照してください。また、* Alice、4 *、Alice、5 *などの複数のエントリがある場合はどうなりますか。あなたのニーズに合ったものがあれば十分だと思います。 – Eugene

+0

実際に私の場合は、とにかくシャッフルされていません。 :)それであなたの答えは簡単になりますか?もしそうなら、それをあなたの答えに加えることができますか? pls dntは現在のものを削除します。 :)) –

関連する問題