2017-01-10 3 views
0

У меня есть два списка. Один показывает количество успешных попыток для каждого человека в группе людей для какой-либо игры.Параллельный цикл с потоками 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; 

И предположим, что я заполнил первые два списка, как это.

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. Поэтому мне действительно нужен такой результат для списка List<PercentageSuccess> percentage.

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

И я хочу, чтобы вычислить их (процент Алисы и Боба процент) в параллельно (я знаю, как сделать последовательно, используя цикл). Как я могу добиться этого с помощью Java Streams (или любого другого простого способа)?

+0

процент Алисы должно быть 4/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 более простым. не так ли? это их любая причина идти с твоими не Aetoros ?? :)) –

+1

Если ваши данные сохранены точно в том же порядке, и вы уверены, что даже в будущем заказ не будет смешанным, то вы, безусловно, можете пойти с ответом Aetoros :) На самом деле, лучше пойти с этим как индекс, основанный лучше, чем создание карты. Кроме того, просто убедитесь, что в списке successAttempts определенно будет запись для каждого значения totalAttempts (скажем, не были успешные попытки, будет ли, по крайней мере, значение 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()) 

Это означает, что вы должны создать метод или custructor для PercentageSuccess который construncts процент при заданных 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 для index'th person (обратите внимание, что вы должны задумать, что списки имеют одинаковый размер и не перетасовываются, иначе мой код неверен).

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

и, наконец, повернуть поток в список с

.collect(Collectors.toList()) 

Кроме того, этот подход не является оптимальным в случае success или total являются LinkedList или другой реализации списка с O (N) стоимости доступа к элементу по индексу ,

+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 видит свои комментарии .. о вводе не перепутаны, также, что произойдет, если есть несколько записей вроде: * Алиса, 4 *, а затем * Алиса, 5 *. независимо от ваших потребностей, достаточно хорошо, не передумайте. – Eugene

+0

Фактически в моем случае он не перетасован в любом случае. :)), так это сделает ваш ответ проще? если бы вы могли добавить это к своему ответу? PLS dnt удалить текущий. :)) –

Смежные вопросы