Соберите элементы в скобки (текущая и все предыдущие группы) - PullRequest
0 голосов
/ 16 октября 2018

(Извините, если термин "скобка" сбивает с толку, я взял его из "налоговых скобок" в переводе с голландского).

Как я могу собирать предметы в группы и каждую предыдущую группу на основе порога свойства?

Пример:

Loan A, duration of 6 months
Loan B, duration of 10 months
Loan C, duration of 12 months

Результат как Map<Integer, List<Loan>>:

6 -> {A, B, C}
10 -> {B, C}
12 -> {C}

В настоящее время я иду по маршруту LinkedHashMap, а затем послесобирая элементы из потока, пропустите все группы, чтобы обновить их:

Map<Integer, List<Loan>> loansByDuration = loans.stream()
        .collect(groupingBy(Loan::getDuration, LinkedHashMap::new, toList()));

List<Loan> previousGroup = null;
for (List<Loan> currentGroup : loansByDuration.values()) {
    if (previousGroup != null) {
        currentGroup.addAll(previousGroup);
    }
    previousGroup = currentGroup;
}

Так что я делаю, чтобы каждое последующее значение списка на карте имело все предыдущие кредиты плюс кредиты, относящиеся только к соответствующимпродолжительность ключ.Похож на кумулятивные промежуточные итоги.

Можно ли это сделать с помощью стандартного API или чего-то подобного пользовательскому сборщику?

Ответы [ 2 ]

0 голосов
/ 17 октября 2018

Для варианта использования необходимо работать с типом типа Map<Integer, List<Loan>>?Таким образом, каждый список будет иметь все предыдущие кредиты .Это означает, что будут избыточные ссылки на Loan.

. Или это вариант использования для предоставления представлений для loans, сгруппированный по duration?
. В таком случае мы можем использовать альтернативный подход:Взгляд на кредиты с использованием Stream (на основе Java 9 +).

public class Loans {

    private final List<Loan> loans;

    public Loans(List<Loan> loans) {
        this.loans = loans.stream()
                .sorted(Comparator.comparingInt(Loan::getDuration))
                .collect(Collectors.toList());
    }

    public Stream<Loan> getUpTo(int duration) {
        return loans.stream().takeWhile(l -> l.getDuration() <= duration);
    }

}

Поскольку у нас есть List<Loan>, отсортированный по duration, мы можем использовать Stream.takeWhile, чтобы получить Streamжелаемых Loan с для определенного duration.

Это работает, например, так:

Loans loans = new Loans(List.of(new Loan("A", 6), new Loan("B", 10), new Loan("C", 12));
loans.getUpTo(1); // <empty>
loans.getUpTo(5); // <empty>
loans.getUpTo(6); // Loan("A", 6)
loans.getUpTo(10); // Loan("A", 6), new Loan("B", 10)
loans.getUpTo(11); // Loan("A", 6), new Loan("B", 10)
loans.getUpTo(12); // Loan("A", 6), new Loan("B", 10), Loan("C", 12)
loans.getUpTo(100); // Loan("A", 6), new Loan("B", 10), Loan("C", 12)

В случае, если необходимо List<Loan>, мы все равно можем collect потоковые элементы toList().

0 голосов
/ 16 октября 2018

Самое простое решение, которое я могу придумать, это что-то вроде этого

class Bucket(int limit, List<Loan> elements)

List<Int> buckets = Arrays.asList(6, 10, 12); // The bucket that you want to put items into
buckets.stream.flatMap(bucketLimit -> {
    List<Loan> loans = loans.stream()
        .filter(l -> l.getDuration() <= bucket)
        .collect(Collectors.toList());

    return new Bucket(bucketLimit, loans);
})
.collect(Collectors.toMap(Bucket::limit, Bucket::loans))

Здесь могут быть некоторые синтаксические ошибки, но вы должны быть в состоянии сделать что-то подобное.

...