【问题标题】:grouping objects java 8分组对象java 8
【发布时间】:2016-04-06 07:55:46
【问题描述】:

我有类似下面的东西:

public class MyClass {
private Long stackId
private Long questionId
}

说 100 的集合,其中 stackid 可能与不同的 questionId 重复。 stackId 和 questionId 之间是一对多的关系

是否有 streamy,java 8 方式转换为以下结构:

public class MyOtherClass {
private Long stackId
private Collection<Long> questionIds
}

这将是 25 个的集合,每个实例都有一个包含 4 个 questionId 的嵌套集合。

输入:

[{1,100},{1,101},{1,102},{1,103},{2,200},{2,201},{2,202},{1,203}]

输出

[{1, [100,101,102,103]},{2,[200,201,202,203]}]

【问题讨论】:

  • markhneedham.com/blog/2014/02/23/… - 首先转换为Map&lt;Long, Collection&lt;Long&gt;&gt;,然后将该映射的条目转换为(第二种)MyClass 实例。
  • 我还是不明白 Which would be a collection of 25, 部分。你能扩展吗?您希望集合最多包含 25 个元素吗?剩下的我们该怎么办?
  • @Tunaki 输出的根元素比输入的少,但是每个根元素与子元素(questionIds)之间存在一对多的关系
  • 但是为什么是 25?这个数字是从哪里来的?以及为什么说是 100 个集合
  • 没关系,选择数字只是为了突出减少。可能是 100 万比 1。

标签: java java-8 java-stream


【解决方案1】:

使用 Stream API 的直接方式涉及 2 个 Stream 管道:

  • 第一个创建一个临时的Map&lt;Long, List&lt;Long&gt;&gt;stackIdquestionIds。这是通过groupingBy(classifier, downstream) 收集器完成的,我们根据stackId 进行分类,具有相同stackId 的值映射到它们的questionId(使用mapping)并使用toList() 收集到一个列表中。李>
  • 第二个将映射的每个条目转换为 MyOtherClass 实例并将其收集到一个列表中。

假设您有一个构造函数MyOtherClass(Long stackId, Collection&lt;Long&gt; questionIds),示例代码如下:

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());

使用 StreamEx 库,您可以在单个 Stream 管道中执行此操作。该库提供pairingfirst 收藏家。这样可以配对两个收集器并对两个收集的结果执行整理器操作:

  • 第一个只保留分组元素中的第一个 stackId(根据构造,它们都是相同的)
  • 第二个将每个元素映射到它们的questionId 并收集到一个列表中。
  • finisher 操作只是返回MyOtherClass 的一个新实例。

示例代码:

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();

【讨论】:

【解决方案2】:
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()
        )
      )
    );

【讨论】:

    【解决方案3】:

    您可以使用 java8 groupingBy 收集器。像这样:

    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("]");
            });
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2018-10-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-11
      • 1970-01-01
      • 1970-01-01
      • 2020-05-20
      • 1970-01-01
      相关资源
      最近更新 更多