我有两个清单。其中一个显示了一组游戏中每个人的成功尝试次数。
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);
我想在 parallel 中计算它们(Alice的百分比和Bob的百分比)(我知道如何使用循环顺序执行)。我如何使用Java Streams(或任何其他简单方法)实现这一目标?
答案 0 :(得分: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);
答案 1 :(得分: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())
这意味着您必须为PercentageSuccess创建一个方法或custructor,它会占用给定SuccessAttempts和TotalAttempts的百分比。
PercentageSuccess(SuccessfulAttempts success, TotalAttempts total) {
this.name = success.name;
this.percentage = (float) success.successCount / (float) total.totalCount;
}
然后构造一个从0到大小并行的整数流:
IntStream.range(0, size).parallel()
这实际上是并行循环。然后将每个整数转换为索引的第二个人的PercentageSuccess(请注意,您必须确保列表具有相同的大小而不是洗牌,否则我的代码不正确)。
.mapToObj(index -> new PercentageSuccess(success.get(index), total.get(index))
最后使用
将Stream转换为List.collect(Collectors.toList())
此外,如果success
或total
是LinkedList或其他列表实现,并且按索引访问元素的成本为O(n),则此方法不是最佳的。
答案 2 :(得分: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());
}