【问题标题】:Java Collectors: Grouping a list of Object into a list of other objects with calculated valuesJava收集器:将对象列表分组为具有计算值的其他对象列表
【发布时间】:2018-12-09 08:37:30
【问题描述】:

我最近接触了 Java 8 及其 Stream API,最近又接触了它的 Collectors API,我发现它有潜力对流进行许多转换,但我有一种情况我没有确定是否可以使用 java 8 甚至可能。我有两个课程:

public class ClassA{
    public int group
    public int id
    public String title
    public String description
    public String keyword
    public String specialValue
}

public class ClassB{
    public String newTitle
    public String joinedDescriptions
}

我想知道是否可以从 ClassA 对象列表生成 ClassB 对象的分组列表,其值是从 ClassA 的字段中计算出来的。具体来说:

  • 通过 group 和 id 的组合对 ClassA 进行分组
  • 当关键字 = 1 时,分组的 ClassB 实例将有一个 newTitle = title,或者当关键字 = 2 时有一个 newTitle = specialValue
  • 最后加入Descriptions,是来自分组的ClassA实例的所有描述的串联。

我知道可以使用 Collectors 的 groupingBy 使用排序 classA -> String.valueOf(classA.group) + String.valueOf(classA.id) 或类似的 lambda 对 ClassA 实例进行分组,但我不'不知道为每个分组实例实现其他计算值。

我希望它解释得足够清楚。

【问题讨论】:

  • 预期的输出是什么? Map<Integer,Map<Integer,ClassB>>?并且根据ClassA的哪个实例来确定对应ClassBnewTitle(因为同一个组可以有多个实例)?
  • 在 B 中添加一个构造函数,该构造函数采用 A 列表并在该构造函数中实现您的规则
  • 我对问题进行了改写和扩展,以包含有关规则的更具体细节,现在应该更加清晰和准确。
  • 嗨,Kev,我已经回滚了你所做的编辑,因为你已经完全改变了这篇文章的上下文。请考虑尝试提出一个新问题,我和现场其他人将愿意提供帮助。

标签: java java-8 java-stream collectors


【解决方案1】:

以下是要采取的步骤;类似于@Joakim Danielson 在 cmets 中提到的内容:

按照您在帖子中提到的方式对源列表进行分组,然后在 ClassB 中添加一个构造函数,该构造函数采用 ClassA 列表,然后执行您在设置标题和加入说明:

所以这将是您的流管道:

List<ClassB> result = source.stream()
                .collect(groupingBy(s -> s.getGroup() + "" + s.getId())) // Map<String, List<ClassA>>
                .values()  // Collection<List<ClassA>>
                .stream() // Stream<List<ClassA>>
                .map(ClassB::new) // Stream<ClassB>
                .collect(Collectors.toList()); //List<ClassB>>

你需要在 ClassB 中定义一个构造函数:

public ClassB(List<ClassA> source) {
        ClassA item = source.get(0);
        if(“1”.equals(item.getKeyword())
             this.newtitle = item.getTitle();
        else if(“2”.equals(item.getKeyword())
             this.newtitle = “specialValue”; // or make a call to a method to compute the value
        this.joinedDescriptions = String.join(“, “, source.stream().map(ClassA::getDescription).collect(toList()));
}

【讨论】:

  • 我已经用更多细节扩展了这个问题,以防可以调整答案以记住这些。但无论如何,这给了我一些很好的方向,让它现在可以工作,所以非常感谢。
  • @KevS 1) 避免在有人回答后完全更改帖子的要求,因为这会使答案不再有效。我要回滚帖子。 2)你的这个编辑值得一个全新的问题,不要忘记在发布之前发布你的尝试,否则如果你只是列出要求但没有表现出任何努力,观众不会接受它。 3) 我已经为您的初始帖子编写了足够多的代码,所以我将提出一个新问题您的需求。
  • 好的,很公平。对不起新手的错误。
  • 强烈建议不要使用对象的字符串连接来生成密钥。这很容易出错,尤其是,因为在这种特定情况下,两者都是 int 数字,所以连接起来,例如1234512345,只是一个等待发生的错误。只需使用groupingBy(s -&gt; Arrays.asList(s.getGroup(), s.getId())) 即可获得没有歧义的密钥,甚至更高效,因为它避免了昂贵的字符串操作。
  • @Holger 好喊声!,直到你提到它,我才想到这一点。对于未来的解决方案,我会牢记这一点。谢谢。
猜你喜欢
  • 2022-11-17
  • 1970-01-01
  • 1970-01-01
  • 2011-02-11
  • 1970-01-01
  • 2011-10-22
  • 2010-10-18
  • 2019-10-07
  • 1970-01-01
相关资源
最近更新 更多