Суммировать содержимое списка с одинаковым содержанием - PullRequest
2 голосов
/ 21 февраля 2020

У меня есть sortedList из типа "Details", который имеет следующее содержимое:

[0]=Details test0: 28.01.2020
[0]=Details test1: 1234
[0]=Details test2: abcd
[0]=Details test3: 1
[0]=Details test4: 20.6
[0]=Details test5: 20.20

[1]=Details test0: 28.01.2020
[1]=Details test1: 1234
[1]=Details test2: abcd
[1]=Details test3: 1
[1]=Details test4: 20.6
[1]=Details test5: 20.20

[2]=Details test0: 29.01.2020
[2]=Details test1: 1234
[2]=Details test2: abcd
[2]=Details test3: 1
[2]=Details test4: 20.7
[2]=Details test5: 20.20

Теперь отсортированный список возвращает все эти объекты, но я хочу суммировать все с тем же test0, test1, test2 и сумма test3, test4 и test5 (test3 + test3, test4 + test4 и test5 + test5):

[0]=Details test0: 28.01.2020
[0]=Details test1: 1234
[0]=Details test2: abcd
[0]=Details test3: 2
[0]=Details test4: 41.2
[0]=Details test2: 40.40

[1]=Details test0: 29.01.2020
[1]=Details test1: 1234
[1]=Details test2: abcd
[1]=Details test3: 1
[1]=Details test4: 2.7
[1]=Details test5: 20.20

Я не уверен, является ли list.stream().filter лучшим вариантом для этой проблемы. Любые идеи? два метода, которые должны найти все дубликаты test0:

    public static List<Detail> getDuplicates(final List<Detail> list) {
    return getDuplicatesMap(list).values()
        .stream()
        .filter(duplicates -> duplicates.size() > 1)
        .flatMap(Collection::stream)
        .collect(Collectors.toList());
}

private static Map<String, List<Details>> getDuplicatesMap(List<Details> list) {
    return list.stream().collect(Collectors.groupingBy(Details::test0));
}

Ответы [ 2 ]

1 голос
/ 21 февраля 2020

То, что вы ищете, - это объединение повторяющихся записей на основе нескольких атрибутов, а не просто идентификация дубликатов. Использование Collectors.toMap с mergeFunction должно помочь вам решить эту проблему.

public static List<Details> getDuplicates(final List<Details> list) {
    return new ArrayList<>(list.stream()
            .collect(Collectors.toMap(dtl -> 
                            Arrays.asList(dtl.getTest0(), dtl.getTest1(), dtl.getTest2()), 
                    Function.identity(), Details::mergeDuplicates))
            .values());
}

, где предполагается, что функция слияния использует специфицированные по типу c Number s, которые можно добавить следующим образом:

static Details mergeDuplicates(Details a, Details b) {
    return new Details(a.getTest0(), a.getTest1(), a.getTest2(),
            a.getTest3() + b.getTest3(), a.getTest4() + b.getTest4(), a.getTest5() + b.getTest5());
}
0 голосов
/ 21 февраля 2020

Ну, пока мы не знаем, что означает «сумма свойств», все, что я могу сделать, это дать вам быстрый пример того, как суммировать вещи, разделяющие одно и то же «число теста».

final List<Details> detailses = ...; // Whatever you currently have.

detailses.stream()

        // Group by 'test number'.
        // This will return a Map<Integer, List<Details>>
        // The key is the test number, and the List contains all matching Details
        .collect(Collectors.groupingBy(Details::getTestNumber))

        // Stream over the entries of this grouped map
        .entrySet().stream()

        // And collect it to another Map
        .collect(Collectors.toMap(
            Map.Entry::getKey, // Keys stay the same

            // Values are mapped to the 'sum' of the properties...
            // However you choose to define that
            entry -> entry.getValue().stream()
                    .map(Details::getProperty)
                    .collect(/* Define summing the property here ... */)
        ));

Это будет в результате получаем Map<Integer, ?>, где ключами являются номера тестов, а значения являются суммой всех свойств для Details с этим номером теста.

...