grouping objects java 8

前端 未结 3 1996
鱼传尺愫
鱼传尺愫 2021-01-13 09:56

I have something like the below :

public class MyClass {
private Long stackId
private Long questionId
}

A collection of say 100, where the

相关标签:
3条回答
  • 2021-01-13 10:36
    List<MyClass> inputs = Arrays.asList(
        new MyClass(1L, 100L),
        new MyClass(1L, 101L),
        new MyClass(1L, 102L),
        new MyClass(1L, 103L),
        new MyClass(2L, 200L),
        new MyClass(2L, 201L),
        new MyClass(2L, 202L),
        new MyClass(2L, 203L)
    );
    
    Map<Long, List<Long>> result = inputs
        .stream()
        .collect(
          Collectors.groupingBy(MyClass::getStackId,
            Collectors.mapping(
              MyClass::getQuestionId, 
              Collectors.toList()
            )
          )
        );
    
    0 讨论(0)
  • 2021-01-13 10:37

    The straight-forward way with the Stream API involves 2 Stream pipelines:

    • The first one creates a temporary Map<Long, List<Long>> of stackId to questionIds. This is done with the groupingBy(classifier, downstream) collectors where we classify per the stackId and values having the same stackId are mapped to their questionId (with mapping) and collected into a list with toList().
    • The second one converts each entry of that map into a MyOtherClass instance and collects that into a list.

    Assuming you have a constructor MyOtherClass(Long stackId, Collection<Long> questionIds), a sample code would be:

    Map<Long, List<Long>> map = 
        list.stream()
            .collect(Collectors.groupingBy(
                MyClass::getStackId,
                Collectors.mapping(MyClass::getQuestionId, Collectors.toList())
            ));
    
    List<MyOtherClass> result = 
        map.entrySet()
           .stream()
           .map(e -> new MyOtherClass(e.getKey(), e.getValue()))
           .collect(Collectors.toList());
    

    Using StreamEx library, you could do that in a single Stream pipeline. This library offers a pairing and first collectors. This enables to pair two collectors and perform a finisher operation on the two collected results:

    • The first one only keeps the first stackId of the grouped elements (they will all be the same, by construction)
    • The second one mapping each element into their questionId and collecting into a list.
    • The finisher operation just returns a new instance of MyOtherClass.

    Sample code:

    import static java.util.stream.Collectors.collectingAndThen;
    import static java.util.stream.Collectors.mapping;
    import static java.util.stream.Collectors.toList;
    import static one.util.streamex.MoreCollectors.first;
    import static one.util.streamex.MoreCollectors.pairing;
    
    // ...
    
    Collection<MyOtherClass> result = 
        StreamEx.of(list)
                .groupingBy(
                    MyClass::getStackId,
                    pairing(
                        collectingAndThen(mapping(MyClass::getStackId, first()), Optional::get),
                        mapping(MyClass::getQuestionId, toList()),
                        MyOtherClass::new
                    )
                ).values();
    
    0 讨论(0)
  • 2021-01-13 10:38

    You can use the java8 groupingBy collector. Like this:

    import org.junit.Test;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Set;
    import java.util.stream.Collectors;
    
    public class RandomTest {
    
        class MyClass {
            private Long stackId;
            private Long questionId;
    
            public MyClass(Long stackId, Long questionId) {
                this.stackId = stackId;
                this.questionId = questionId;
            }
    
            public Long getStackId() {
                return stackId;
            }
    
            public Long getQuestionId() {
                return questionId;
            }
        }
    
        public class MyOtherClass {
            private Long stackId;
            private Set<Long> questionIds;
    
            public MyOtherClass(Long stackId, Set<Long> questionIds) {
                this.stackId = stackId;
                this.questionIds = questionIds;
            }
    
            public Long getStackId() {
                return stackId;
            }
    
            public Set<Long> getQuestionIds() {
                return questionIds;
            }
        }
    
        @Test
        public void test() {
            List<MyClass> classes = new ArrayList<>();
            List<MyOtherClass> otherClasses = new ArrayList<>();
    
            //populate the classes list
            for (int j = 1; j <= 25; j++) {
                for (int i = 0; i < 4; i++) {
                    classes.add(new MyClass(0L + j, (100L*j) + i));
                }
            }
    
            //populate the otherClasses List
            classes.stream().collect(Collectors
                    .groupingBy(MyClass::getStackId, Collectors.mapping(MyClass::getQuestionId, Collectors.toSet())))
                    .entrySet().stream().forEach(
                    longSetEntry -> otherClasses.add(new MyOtherClass(longSetEntry.getKey(), longSetEntry.getValue())));
    
            //print the otherClasses list
            otherClasses.forEach(myOtherClass -> {
                System.out.print(myOtherClass.getStackId() + ": [");
                myOtherClass.getQuestionIds().forEach(questionId-> System.out.print(questionId + ","));
                System.out.println("]");
            });
        }
    }
    
    0 讨论(0)
提交回复
热议问题