Home > Enterprise >  Stream api to spilt ArrayList in batches based on conditions
Stream api to spilt ArrayList in batches based on conditions

Time:10-16

Given the following example seed:

    List<EmailGroupingDataDTO> emailDataToGroup = Arrays.asList(
            buildEmailGroupingDto(1L, "member_number_1", "username_1", "group_code_1"),
            buildEmailGroupingDto(2L, "member_number_1", "username_1", "group_code_1"),
            buildEmailGroupingDto(3L, "member_number_1", "username_2", "group_code_1"),
            buildEmailGroupingDto(4L, "member_number_1", "username_2", "group_code_1"),
            buildEmailGroupingDto(5L, "member_number_1", "username_2", "group_code_3"),
            buildEmailGroupingDto(6L, "member_number_2", "username_1", "group_code_1"),
            buildEmailGroupingDto(7L, "member_number_2", "username_1", "group_code_2"),
            buildEmailGroupingDto(8L, "member_number_2", "username_1", "group_code_2"),
            buildEmailGroupingDto(9L, "member_number_3", "username_1", "group_code_1"),
            buildEmailGroupingDto(10L, "member_number_3", "username_1", "group_code_1"),
            buildEmailGroupingDto(11L, "member_number_3", "username_1", "group_code_2"),
            buildEmailGroupingDto(12L, "member_number_3", "username_1", "group_code_2"),
            buildEmailGroupingDto(13L, "member_number_3", "username_1", "group_code_3"),
            buildEmailGroupingDto(14L, "member_number_4", "username_1", "group_code_3"),
            buildEmailGroupingDto(15L, "member_number_4", "username_1", "group_code_3")
    );

I want to create a List of Lists (batches) based on whether either one of the following properties changes when iterating through the list:

private boolean isEmailDataEqual(EmailGroupingDataDTO currDto, EmailGroupingDataDTO nextDto) {
    return currDto.getMemberNumber().equals(nextDto.getMemberNumber())
        && currDto.getUsername().equals(nextDto.getGroupCode())
        && currDto.getGroupCode().equals(nextDto.getGroupCode());
}

Through regular iteration I can manage this myself probably.
However the question I have is whether there is a stream api that can manage this declaratively.

CodePudding user response:

StreamEx will do this for you:

List<List<EmailGroupingDataDTO>> groups = StreamEx.of(emailDataToGroup)
        .groupRuns(this::isEmailDataEqual)
        .toList();

CodePudding user response:

You could use AtomicInteger & AtomicReference for the classifier of Collectors.groupingBy and build a map (and get the grouped batches using Map.values). Integer as group key and reference as a representative element of a group and to enable an easy way of comparison for your attributes.

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;

....


List<EmailGroupingDataDTO> emailDataToGroup = //your list 

AtomicInteger ai = new AtomicInteger();
AtomicReference<EmailGroupingDataDTO> myRef = new AtomicReference<>(emailDataToGroup.get(0));

Collection<List<EmailGroupingDataDTO>> result =  
        emailDataToGroup.stream().collect(Collectors.groupingBy(myDto -> {
            boolean equal = isEmailDataEqual(myDto, myRef.get());
            if (!equal) myRef.getAndSet(myDto);
            return equal ? ai.get() : ai.incrementAndGet();
        })).values();

NOTE: as @shmosel pointed out correctly, this approach will only work if you stream over your list sequentally.

  • Related